2012-10-11 148 views
2

我有一个项目模型和一个开发人员模型。我有计算某个项目的“兴趣”为一个特定的开发商的概念:覆盖AR订单范围

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) 

我不知道如何做到这一点,虽然,因为这不是明显对我如何覆盖范围。有什么建议?

回答

0

假设你将不再需要使用标准的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 
+0

你是说这是不可能覆盖'order',使其返回如果'options'传递我的客户订单的结果,但如果返回'选择本地订购操作结果'是空的? –

+0

完全不可能,使用别名肯定是可行的。由于公约的变化,不推荐参加严肃的项目。更新以演示这一点。 – PinnyM