Rails named_scope继承?

时间:2011-05-05 11:52:09

标签: ruby-on-rails inheritance activerecord named-scope

我试图通过提供一个继承的公共基础模型来概括我的一些模型,其中包含一些相互的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控制台中可以正常工作。任何想法如何修补这个?感谢。

1 个答案:

答案 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