How to always use the base class and ignore STI in Rails?
Asked Answered
S

2

11

I have a module that I'm including in several models with this content:

self.class.find_by_foo(bar)

Everything was fine until I started using STI. That line should always generate the query

select * from table where foo=bar"

and not

select * from table where foo=bar AND type="Whatever"

Is there a simple way to avoid it?

I though of two solutions. Walking up the class hierarchy until I find the top-most class before ActiveRecord::Base or run the query by hand, like:

self.class.find_by_sql("select * from #{self.class.table_name} where foo=bar")

I don't like either solution. Is there a better one?

Stefanistefania answered 11/2, 2012 at 17:52 Comment(0)
E
29

First, you can always get to the base class with the method base_class:

self.class.base_class.find_by_foo(bar)

However, in your example above, you shouldn't have to access the base class. You can just do the following and Rails will know the correct table name:

self.class.where(:foo => bar)

There are actually very few cases when you need to access the base class.

Ernestoernestus answered 16/10, 2012 at 20:16 Comment(1)
In Rails 4 self.class unexpectedly returned the objects parent class, in Rails 5 self.class returns, as excepted, the models class. self.class.base_class can be used to get the parent class.Manganin
S
2

Until there's a better answer, I'm using this code to find the base class of the STI chain:

klass = self.class
self.class.ancestors.each do |k|
  if k == ActiveRecord::Base
    break # we reached the bottom of this barrel
  end
  if k.is_a? Class
    klass = k
  end
end
Stefanistefania answered 11/2, 2012 at 18:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.