如何通过SQL中没有属性的自定义模型方法进行排序?
以前我订购过我的post:
@posts = Post.find(:all, :order => "created_at DESC")
但是现在我想用我在Post模型中编写的自定义方法替换created_at
,该方法给出了一个数字作为结果。
我猜:
@posts = Post.find(:all, :order => "custom_method DESC")
哪个失败..
它失败是因为您要求您的数据库进行排序。
@posts = Post.all.sort {|a,b| a.custom_method <=> b.custom_method}
请注意,当您想要开始分页结果并且不再希望获取.all
时,这变得非常简单。 在你使用它之前先考虑一下你的设计。
只是为了扩展@Robbie的答案
Post.all.sort_by {|post| post.custom_method }.reverse
正如第一个答案所指出的那样,order是一个Active Record命令,它基本上对您的数据库执行SQL查询,但该字段实际上并不存在于您的数据库中。
正如其他人评论的那样,你可以通过使用&符号来更干净地运行Ruby方法sort_by( 这里有更多信息):
Post.all.sort_by(&:custom_method)
但是,根据您在视图中的操作,事情会变得复杂。 我将分享我最近做的一个案例,以防止你思考你的问题。 我需要通过另一个名为“categories”的资源对我的资源进行分组,然后通过“netvotes”对原始资源进行排序,这是一个自定义模型方法,然后按名称排序。 我做到了:
- 在控制器中按名称排序:
@resources = Resource.order(:name)
- 在视图的外部循环中按类别分组:
<% @resources.group_by(&:category).each do |category, resources| %>
<% @resources.group_by(&:category).each do |category, resources| %>
- 然后通过部分资源中的投票对资源进行排序:
<%= render resources.sort_by(&:netvotes).reverse %>
视图有点令人困惑,所以这里是index.html.erb中的完整视图循环:
<% @resources.group_by(&:category).each do |category, resources| %> <%= category.name %>
<%= render resources.sort_by(&:netvotes).reverse %> <% end %>
这是_resource.html.erb部分:
<%= link_to fa_icon('chevron-up lg'), upvote_resource_path(resource), method: :put %>
<%= resource.netvotes %>
<%= link_to fa_icon('chevron-down lg'), downvote_resource_path(resource), method: :put %> <%= link_to resource.name, resource.link, target: "_blank" %> <%= resource.notes %>
好吧,只需Post.find(:all)
就会返回一个AR对象数组。 因此,您可以使用Array.sort_by并将其传递给一个块,并且由于已经提取了这些记录,因此您可以访问sort_by所采用的块内的虚拟属性。
RDoc: Enumerable.sort_by
这比我喜欢的要复杂一点,但是我喜欢保持我的排序作为一个活跃的记录模型,所以它有点复杂而不仅仅是
Post.all.sort_by {|post| post.custom_method }
我所做的是:
ids = Post.all.sort_by {|post| post.custom_method }.map(&:ids) Post.for_ids_with_order(ids)
这是Post模型中的自定义范围
#app/models/post.rb class Post < ApplicationRecord ... scope :for_ids_with_order, ->(ids) { order = sanitize_sql_array( ["position(id::text in ?)", ids.join(',')] ) where(:id => ids).order(order) } ... end
我希望这有帮助
在rails 3中我们可以这样做: Post.order("custom_method DESC")
将应用程序从rails2升级到rails3时