通过模块共享范围?

All*_*ate 22 activerecord scope rspec ruby-on-rails activemodel

我想通过将共享范围移动到模块中来干掉几个模型,例如:

module CommonScopes
  extend ActiveSupport::Concern

  module ClassMethods
    scope :ordered_for_display, order("#{self.to_s.tableize}.rank asc")
  end
end
Run Code Online (Sandbox Code Playgroud)

我还想创建测试模块的共享规范.不幸的是,当我尝试在我的模型中包含共享范围时,我得到:

undefined method `order' for CommonScopes::ClassMethods:Module
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?谢谢!

mde*_*lin 51

与rails 4 作用域语法一样,您可以简单地使用lambda来延迟代码的执行(也可以在rails 3中运行):

module CommonScopes
  extend ActiveSupport::Concern

  included do
    scope :ordered_for_display, -> { order("#{self.to_s.tableize}.rank asc") }
  end
end
Run Code Online (Sandbox Code Playgroud)


Gaz*_*ler 13

您可以使用instance_eval

module CommonScopes
  extend ActiveSupport::Concern

  def self.included(klass)
    klass.instance_eval do
      scope :ordered_for_display, order("#{self.to_s.tableize}.rank asc")
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 这也有点错误,因为它使扩展 ActiveSupport::Concern 的点无效。作用域应该放在一个像 `included do; 那样的块中。... end` 因为它是 ActiveRecord::Concern 的一部分,或者我们不应该费心扩展它,因为上面的 `self.included` 语法内置于每个 Ruby 模块中,与 ActiveSupport::Concern 无关。理想情况下,我们选择一种或另一种方式,因为 ActiveSupport::Concern 负责处理我们在此答案示例中重新实现的样板代码。这适用于 Rails 3 和 4,如 mdemolin 的回答 (2认同)