I’m trying to generalize some of my models by providing a common base model to inherit from that contains some mutual named_scope declarations and a filter method that activates that search for simpler querying on the controller side. This appears to be working when I run it in the console, but fails when in the controller:
# in the base model
class GenericModel < ActiveRecord::Base
named_scope :by_name, lambda { |name|
( name.blank? ) ? {} : { :conditions => [ "#{self.table_name}.name like ?", "%#{name}%" ] }
}
def filter(params)
res = []
res = self.by_name( (params[:name] or '') ) if params[:name]
return res
end
end
class MyModel < GenericModel
set_table_name 'my_models'
end
# works in in console!
>> params = { :name => 'jimmy' }
>> MyModel.filter(params)
=> [ <#MyModel ...>, ... ]
nil
# fails in controller
@model = MyModel.filter(params)
# ActiveRecord::StatementInvalid (Mysql::Error Unknown column 'generic_models.name' in where clause...)
Apparently the parent class’ named_scope is being called when in rails, but works fine in rails console. Any ideas how to mend this? thanks.
That’s a bit of a train-wreck because of the way ActiveRecord is trying to interpret what you’re saying. Generally the first class derived from ActiveRecord::Base is used to define what the base table name is, and sub-classes of that are defined to use Single Table Inheritance (STI) by default. You’re working around this by using
set_table_namebut, as is often the case, while it’s possible to go against the grain in Rails, things often get messy.You should be able to do this a lot more cleanly using a mixin as suggested by Beerlington.
You should be able to keep your extensions contained to that module. If you want to clean this up even further, write an initializer that defines a method like
scoped_by_namefor ActiveRecord::Base that triggers this behavior:Then you can tag all classes that require this: