Rails - 不要在范围定义上重复自己

时间:2014-08-01 09:20:18

标签: ruby-on-rails ruby-on-rails-4 has-many

以下是示例模型:

class Book < AR::Base
  has_many :pages

  scope :with_some_conditions, ->(var) {
    where(... something with var ...)
    .joins(... some joins ...)
  }
end

class Page << AR::Base
  # Attrs : a, b (integers)
  belongs_to :book

  scope :with_c, {
    select("#{Page.table_name}.*, (a+b) AS c")
  }

  def c; a+b; end
end

我想要获得具有最大pages值的10 c,属于books尊重某些条件。

此代码正常运行:

Book.with_some_conditions('foo').map(&:pages).map(&:c)[0...10]

或更好

Book.with_some_conditions('foo').includes(:pages).map(&:pages).map(&:c)[0...10]

现在假设c方法不是+的简单方法,但它是一个真正更复杂的函数(带连接和其他一些东西)。这段代码尽可能不优化......所有c必须在Rails中计算和排序...... SQL可能会有所帮助。

Page模型中定义范围是我找到的更好的解决方案:

scope :big_scope, ->(var) {
  joins(:book)
  .where(... something with var ...) # The 2 lines are C/P from Book model
  .joins(... some joins ...)
  .select("#{Page.table_name}.*, (a+b) AS c")
}

然后,致电Page.big_scope('foo').order(:c => :desc)完美无缺。

问题是我在重复自己:完整的范围在2个不同的类中写了2次。

  .where(... something with var ...)
  .joins(... some joins ...)

是否有通过关系“调用”范围的方法?

此致

1 个答案:

答案 0 :(得分:1)

这是标准模块&#39;模板&#39;如果我想在两个或更多类之间共享方法,我会使用。

module MyModule
  def self.included(base)
    base.extend(ClassMethods)
    base.class_eval do 
      #associations, callbacks, scopes, validations etc go here
    end
  end

  #instance methods go here

  module ClassMethods
    #class methods go here
  end    
end