如何在 Rails 3 中订购包含的元素

Posted

技术标签:

【中文标题】如何在 Rails 3 中订购包含的元素【英文标题】:How to order included elements in Rails 3 【发布时间】:2011-07-17 21:56:39 【问题描述】:

我有一个模型关系,其中today 有很多tasks

我正在尝试检索用户的 today 对象,包括 tasks 并将它们全部呈现给 Json。所有这一切都很顺利,直到我决定在today 对象中订购tasks,因为respond_with block 也用于呈现html 页面。有什么方法可以包含tasks 并订购它们?

我正在尝试这样的事情:

class TodaysController < ApplicationController
  respond_to :html, :json
  def show
    @today = Today.where(:user_id => current_user.id).joins(:tasks).includes(:tasks).order(:priority).first
    respond_with @today, :include => :tasks
  end
end

这会正确检索所有内容,但似乎根本没有对任务进行排序。

这是我曾经拥有的(效果很好,但没有订购):

class TodaysController < ApplicationController
  respond_to :html, :json
  def show
    @today = current_user.today
    respond_with @today, :include => :tasks
  end
end

我知道我可以像这样检索数据并在之后对其进行排序:

@today = current_user.today
@today.tasks.sort!|a,b| a.priority <=> b.priority 

这可行并且会通过我的测试,但我希望有一种 ActiveRecord 方法来解决这个问题。

【问题讨论】:

关于你的最后一行代码。下面稍微清楚一点:@today.tasks.sort_by(&amp;:priority). 【参考方案1】:

在您的 Today 模型中试试这个:

has_many :tasks, :order => 'priority DESC'

编辑:正如下面评论中提到的,在 Rails 4+ 中,现在是:

has_many :tasks, ->  order(:priority => :desc) 

(more info here)

【讨论】:

没有其他办法吗? 在 Rails 4 中,现在已弃用,新方法将是 has_many :tasks, -&gt; order(:priority =&gt; :desc) read about it here【参考方案2】:

直接的解决方案是在priority 之前包含tasks 表名:

Today.where(:user_id => current_user.id).includes(:tasks).order('tasks.priority').first
# joins(:tasks) is not required

或者,如果您不想硬编码表名,您可以与Task 模型的范围合并:

Today.where(:user_id => current_user.id).joins(:tasks).includes(:tasks).merge(Task.order(:priority)).first
# joins(:tasks) here is required

此外,您可以将 has_many: todays 添加到 User 模型以放弃 where 子句并执行以下操作:

current_user.todays.includes(:tasks).order('tasks.priority').first
# or
current_user.todays.joins(:tasks).includes(:tasks).merge(Task.order(:priority)).first

但如果您只需要/总是按优先级排序,而不需要其他不同的排序,则将order 添加到has_many :tasks 会更容易。

【讨论】:

我不明白为什么将订单添加到模型中会更好。在我看来,排序是视图的一部分,与任何一个模型都无关。 是的。我的意思是更容易。已编辑。 @Jack Today.where(:user_id =&gt; current_user.id).joins(:tasks).includes(:tasks).merge(Task.order(:priority)).first 它不适用于 Rails 4.2 应该可以,现在没有 4.2 来测试它,肯定可以在 5 中使用。无论如何,从 4.0 开始,您实际上应该使用 referencesincludes 来表明您将使用表格查询。所以它应该类似于Today.where(:user_id =&gt; current_user.id).includes(:tasks).references(:tasks).merge(Task.o‌​rder(:priority)).fir‌​st

以上是关于如何在 Rails 3 中订购包含的元素的主要内容,如果未能解决你的问题,请参考以下文章

Rails 3.1 资产管道和手动订购的 Javascript 需要

Rails:在嵌套视图中订购商品

如何通过远距离以外的其他方式订购rails geocoder gem的结果

Rails 3:可以用连接表订购吗?

如何在 python apache Beam 的窗口中订购元素?

与采集订购骨干共同意见