覆盖AR订单范围

时间:2012-10-11 16:18:32

标签: ruby activerecord

我有一个Project模型和一个Developer模型。我有为特定开发人员计算项目“兴趣”的概念:

class Project < ActiveRecord::Base
  def interestingness_for(developer)
    some_integer_based_on_some_calculations
  end
end

我认为它会很整洁,而不是像Project.order_by_interestingness_for(bill)这样的东西,能够说出来

Project.order(:interestingness, :developer => bill)

并且它是一个范围,而不仅仅是一个函数,所以我可以做像

这样的事情
Project.order(:interestingness, :developer => bill).limit(10)

我不知道该怎么做,因为对我来说如何覆盖范围并不明显。有什么建议吗?

1 个答案:

答案 0 :(得分:0)

假设您不需要为Project类使用标准的ActiveRecord order查询方法,您可以像任何其他类方法一样覆盖它:

def self.order(type, options)
  self.send(:"special_#{type}_calculation_via_scopes", options)
end

然后诀窍是确保您创建所需的计算方法(根据您的兴趣和其他算法而有所不同)。并且计算方法仅使用范围或其他AR查询接口方法。如果您不习惯使用查询接口将方法逻辑转换为SQL等效项,则可以尝试使用Squeel DSL gem,它可以根据您的具体计算直接使用该方法。

如果您可能需要经典的order方法(这通常是一个安全的假设),那么请不要覆盖它。为此目的创建代理非ActiveRecord对象,或使用不同的命名约定。

如果你真的想要,你可以使用别名来达到类似的效果,但如果第二个参数(在这种情况下为'options')在Rails进展时突然出现另一个意义,它可能会长期产生意想不到的后果。以下是您可以使用的示例:

def self.order_with_options(type, options = nil)
  if options.nil?
    order_without_options(type)
  else
    self.send(:"special_#{type}_calculation_via_scopes", options)
  end
end    
class << self
  alias_method_chain :order, :options
end