Rails named_scope继承?

sa1*_*125 1 inheritance activerecord named-scope ruby-on-rails

我试图通过提供一个继承的公共基础模型来概括我的一些模型,其中包含一些相互的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...)
Run Code Online (Sandbox Code Playgroud)

显然,在rails中调用父类'named_scope,但在rails控制台中可以正常工作.任何想法如何修补这个?谢谢.

tad*_*man 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
Run Code Online (Sandbox Code Playgroud)

您应该能够将扩展包含在该模块中.如果你想进一步清理它,请编写一个初始化程序,它定义一个类似于scoped_by_nameActiveRecord :: Base 的方法来触发这种行为:

class ActiveRecord::Base
  def scoped_by_name
    extend ByNameExtension
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以标记所有需要此类的类:

class MyModel < ActiveRecord::Base
  scoped_by_name
end
Run Code Online (Sandbox Code Playgroud)