使任何订单可链接

时间:2011-02-20 10:19:11

标签: ruby-on-rails ruby sorting model named-scope

我想根据无法在单个查询中汇总的复杂标准对Person模型对象进行排序 - 因此在命名范围内。现在我使用类方法:

def Person.very_complicated_sorting
  Person.all.sort { |x,y| x.bunch_of_calculations <=> y.bunch_of_calculations }
end

有没有办法让这个可链接? E.g。

Person.tallest.very_complicate_sorting.youngest

其中tallestyoungest是两个命名范围。

3 个答案:

答案 0 :(得分:1)

不幸的是,这是不可能的。

命名范围的工作方式是“懒惰地”构建一组SQL参数,在您实际尝试对它们执行某些操作之前,这些参数不会被评估。例如,以下命名范围链:

people = Person.tallest.youngest

导致运行任何数据库查询,它实际上导致ActiveRecord::NamedScope对象存储在people变量中。只有当您访问或遍历该对象时,才会运行SQL并加载对象。

您的问题是您的排序方法没有在SQL中表达,它是一组Ruby条件。当Rails到达你的sort_by时,它必须去获取并实例化Person对象,以便它可以在它们上运行你的条件。完成后,您将拥有Array个对象,而不再是NamedScope个对象。

答案 1 :(得分:0)

您的very_complicated_sorting应该在Person模型中。

你不能在方法中写Person.all,否则就无法链接。

请保持:

def self.very_complicated_sorting
  sort_by { |x,y| x.bunch_of_calcultaions <=> y.bunch_of_calculations }
end

答案 2 :(得分:0)

如果您使用Sequel而不是ActiveRecord作为数据库库,则可以执行此操作。它允许您在模型上使用def_dataset_method来创建在Datasets上运行的方法(其中包含模型);只要您的方法返回数据集,您就可以根据需要链接它们。例如:

class Person < Sequel::Model
  def_dataset_method :active_only do
    filter :active=>true
  end
  def_dataset_method :sort_much do
    order :name, :age.desc
  end
end

active_peeps = Person.active_only.sort_much
peeps_active = Person.sort_much.active_only

要留在数据集域中,您只需使用可表示为SQL的方法。您不能期望从数据库中请求某些记录,然后在它们上执行复杂的仅​​使用Ruby的逻辑(比如,通过在Ruby Hash中查找的object_id对它们进行排序),然后然后继续在生成的数组上执行SQL。 Ruby不会在您的数据库上运行(pl/Ruby除外)。

或者,您可以直接进入Ruby数组,然后以任何顺序链接您喜欢的任何Ruby方法,如果它们都在数组和返回数组上运行。您必须在代码中明确决定何时从数据库中获取结果,然后再对数组进行操作。