本文介绍了Rails的named_scope继承?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过提供一个共同的基础模型,从继承来概括我的一些机型包含了一些相互named_scope声明,并且激活了搜索控制器端简单的查询过滤器的方法。这似乎是,当我在控制台中运行工作,但失败时控制器:

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...)

显然,父类的named_scope被调用时,在轨,但能正常工作在轨控制台。任何想法如何补呢?谢谢。

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.

推荐答案

这是一个有点列车残骸,因为方式的ActiveRecord试图跨preT你在说什么。从一般的ActiveRecord :: Base的派生第一类是用来定义基表的名称是,而被定义为使用单表继承(STI),默认的子类。您正在解决此通过使用 set_table_name 但是,这是常有的情况下,虽然有可能违背Rails中粮,事情往往会导致混乱。

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_name but, as is often the case, while it's possible to go against the grain in Rails, things often get messy.

您应该可以有很多更清洁使用混入这样做所建议的Beerlington。

You should be able to do this a lot more cleanly using a 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

您应该能够保持载到该模块的扩展。如果您想进一步打扫一下,编写定义如 scoped_by_name A方法的ActiveRecord :: Base的触发此行为的初始化:

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_name for ActiveRecord::Base that triggers this behavior:

class ActiveRecord::Base
  def scoped_by_name
    extend ByNameExtension
  end
end

然后你可以标记需要这一切类:

Then you can tag all classes that require this:

class MyModel < ActiveRecord::Base
  scoped_by_name
end

这篇关于Rails的named_scope继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 04:20