使任何订单可链接
我想根据一个复杂的标准对我的 Person
模型对象进行排序,该标准无法在单个查询中进行总结 - 因此在命名范围内。现在我使用一个类方法,例如:
def Person.very_complicated_sorting
Person.all.sort { |x,y| x.bunch_of_calculations <=> y.bunch_of_calculations }
end
有没有办法使它可链接?例如
Person.tallest.very_complicate_sorting.youngest
,其中 tallest
和 youngest
是两个命名范围。
I want to sort my Person
model objects based on a complicated criterion that can't be summarized in a single query - and so in a named scope. Right now I use a class method like:
def Person.very_complicated_sorting
Person.all.sort { |x,y| x.bunch_of_calculations <=> y.bunch_of_calculations }
end
Is there a way to make this chainable? E.g.
Person.tallest.very_complicate_sorting.youngest
where tallest
and youngest
are two named scopes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不幸的是,这是不可能的。
命名作用域的工作方式是“惰性地”构建一组组合的 SQL 参数,直到您实际尝试使用它们执行某些操作时才会对这些参数进行评估。例如,以下命名范围链:
不会导致任何数据库查询运行,它实际上会导致
ActiveRecord::NamedScope
对象存储在>people
变量。仅当您访问或迭代该对象时,才会运行 SQL 并加载对象。你的问题是你的排序方法不是用 SQL 表达的,而是一组 Ruby 条件。当 Rails 到达您的
sort_by
时,它必须去获取并实例化Person
对象,以便它可以在它们上运行您的条件。完成后,您将拥有一个Array
对象,而不再是NamedScope
对象。This isn't possible unfortunately.
The way named scopes work is by "lazily" building up a combined set of SQL parameters, which aren't evaluated until you actually try to do something with them. So for example the following chain of named scopes:
will not cause any database query to be run, it actually causes an
ActiveRecord::NamedScope
object to be stored in thepeople
variable. Only when you access or iterate through that object is the SQL run and the objects loaded.Your problem is that your sorting method isn't being expressed in SQL, it's a set of Ruby conditions. When Rails gets to your
sort_by
it has to go and fetch and instantiate thePerson
objects so that it can run your condition on them. After it's done that you have anArray
of objects and not aNamedScope
object any more.您的
very_complicated_sorting
应该位于您的Person
模型中。您不能不在方法内写入
Person.all
,否则它无法链接。只需保留:
Your
very_complicated_sorting
should be in yourPerson
model.You musn't not write
Person.all
inside the method, it couldn't be chainable otherwise.Just keep:
如果您对数据库库使用 Sequel 而不是 ActiveRecord,这是可能的。它允许您使用
def_dataset_method
在模型上创建对 数据集 进行操作的方法(其中模型是包括);只要您的方法返回一个数据集,那么您就可以根据需要链接它们。例如:要留在数据集领域需要您仅使用可以表达为 SQL 的方法。您不能期望从数据库中请求某些记录,然后对它们执行复杂的仅 Ruby 逻辑(例如,根据在 Ruby 哈希中查找的
object_id
对它们进行排序),然后 /em> 继续对结果数组执行 SQL。 Ruby 不在您的数据库上运行(pl/Ruby 除外)。或者,您可以直接使用 Ruby 数组,然后以任意顺序链接您喜欢的任何 Ruby 方法(如果它们都对数组进行操作并返回数组)。您必须在代码中明确决定何时从数据库获取结果,然后对数组进行操作。
This is possible if you use Sequel instead of ActiveRecord for your database library. It lets you use
def_dataset_method
on Models to create methods that operate on Datasets (of which Models are included); as long as your methods return a Dataset then you can chain them as you like. For example:To stay in Dataset land requires you to only use methods that can be expressed as SQL. You cannot expect to ask for some records from the database, then perform complex Ruby-only logic on them (say, sorting them by their
object_id
looked up in a Ruby Hash), and then continue to perform SQL on the resulting array. Ruby does not run on your database (other than pl/Ruby).Alternatively, you can go straight to a Ruby array and then chain whatever Ruby methods you like in any order, if they all operate on arrays and return arrays. You must make a clear decision in your code as to when you are going to fetch the results from the Database and then operate on the array afterwards.