我试图通过提供一个继承的公共基础模型来概括我的一些模型,其中包含一些相互的named_scope声明和一个激活搜索的过滤器方法,以便在控制器端进行更简单的查询。当我在控制台中运行它时,它似乎正在工作,但在控制器中时失败:
# 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...)
显然,在rails中调用父类'named_scope,但在rails控制台中可以正常工作。任何想法如何修补这个?感谢。
答案 0 :(得分:5)
由于ActiveRecord试图解释你所说的话,这有点像火车残骸。通常,从ActiveRecord :: Base派生的第一个类用于定义基表名称,并且默认情况下定义它们的子类以使用单表继承(STI)。你正在使用set_table_name
来解决这个问题,但是,通常情况下,虽然Rails可能会违背细节,但事情往往会变得混乱。
你应该能够使用Beerlington建议的mixin更干净地完成这项工作。
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
您应该能够将扩展程序包含在该模块中。如果您想进一步清理它,请编写一个初始化程序,为ActiveRecord :: Base定义类似scoped_by_name
的方法,以触发此行为:
class ActiveRecord::Base
def scoped_by_name
extend ByNameExtension
end
end
然后您可以标记所有需要此类的类:
class MyModel < ActiveRecord::Base
scoped_by_name
end