Rails named_scope inheritance?

I am trying to generalize some of my models by providing a common base model for inheritance containing some named_scope declarations and a filter method that activates this search for a simpler query on the controller side. It seems to work when I run it in the console, but it doesn't work 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 named_scope parent class is called when on rails, but works fine in the rails console. Any ideas how to fix this? thanks.

+1
source share
1 answer

Something like a train wreck due to ActiveRecord trying to interpret what you are saying. Typically, the first class derived from ActiveRecord :: Base is used to determine the name of the base table, and the subclasses that are defined to use Single Table Inheritance (STI) by default. You work around this using set_table_name , but as is often the case, although it can go against the grain in Rails, things often get messy.

You should be able to do this much more cleanly using mixin, as suggested by Beerlington.

 module ByNameExtension def self.extended(base) # This method is called when a class extends with this module base.send(:scope, :by_name, lambda { |name| name.blank? ? nil : where("#{self.table_name}.name LIKE ?", "%#{name}%") }) end def filter(params) params[:name].present? ? self.by_name(params[:name]) : [ ] end end class MyModel < ActiveRecord::Base # Load in class-level methods from module ByNameExtension extend ByNameExtension end 

You should be able to support the extensions contained in this module. If you want to clear this even further, write an initializer that defines a method of type scoped_by_name for ActiveRecord :: Base that calls this behavior:

 class ActiveRecord::Base def scoped_by_name extend ByNameExtension end end 

Then you can mark all classes that require this:

 class MyModel < ActiveRecord::Base scoped_by_name end 
+4
source

All Articles