【问题标题】:Sort ActiveRecord collection by different attributes depending on a third attribute根据第三个属性按不同属性对 ActiveRecord 集合进行排序
【发布时间】:2018-10-23 17:38:49
【问题描述】:

我有一个具有这些属性的 Order 模型:

  • created_at 日期时间
  • delivery_at 日期时间
  • 状态 字符串

我想要做的是根据status 对两个集合按created_atdelivery_at 进行排序。

在模型上,我创建了一个检查状态顺序并返回 created_atdelivery_at 日期时间的方法。

def status_date
  if status == 'on_delivery'
    delivered_at.to_datetime
  else
    created_at.to_datetime
  end
end

然后在控制器中:

created = Order.where(status: 'open')
on_delivery = Order.where(stauts: 'on_delivery')

orders = created + on_delivery
orders.sort_by(&:status_date)

这不起作用。

我正在尝试实现按时间顺序排列的订单列表,但 DateTime 应该与其状态相关。

【问题讨论】:

    标签: ruby-on-rails activerecord rails-activerecord


    【解决方案1】:

    您可以通过一次查询两种状态然后使用 SQL CASE 表达式进行排序,在数据库中完成所有操作:

    case status
    when 'open' then created_at -- if the status is open then use created_at
    else delivered_at           -- otherwise use delivered_at
    end
    

    你只有两个状态,所以这些分支就足够了。

    把它放在一起:

    orders = Order.where(status: %w[open on_delivery])
                  .order(Arel.sql("case status when 'open' then created_at else delivered_at end"))
    

    Arel.sql 是在 Rails5 中获得通过 #order 的 SQL 字符串所必需的(并且在 Rails6 中是强制性的)。

    【讨论】:

    • 我试过了,但它不起作用。我可以构建的最简单的查询是:Order.by_date(date).where(status: %w[open on_delivery]).order(Arel.sql("CASE status WHEN 'open' THEN created_at ELSE delivered_at END"))。 by_date 它只是从给定日期的开始到结束获取的范围。无论如何,查询很好地返回了我的订单,但订单似乎按其状态分组(一个日期我得到 on_delivery-open-on_delivery 分组结果,另一个 open-on_delivery),并且没有任何分组。
    • 那个“最简单”的查询和我的一样,但是你引入了by_date 范围。顺序是时间戳,但使用的时间戳取决于您要查找的 status,对吗?我不知道你的意思是“没有任何分组”。
    • 啊。问题是其他日期即将到来,所以我做了:Arel.sql("case status when 'open' then created_at::time else delivered_at::time end")
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 2019-10-02
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2012-05-18
    相关资源
    最近更新 更多