【问题标题】:Change 'ORDER BY' Chain on ActiveRecord Subset更改 ActiveRecord 子集上的“ORDER BY”链
【发布时间】:2017-03-08 06:48:24
【问题描述】:

背景:

我有 Product 模型,其中包括 4 个类别

class Product < ActiveRecord::Base
  enum category: [:recent, :cheapest, :most_expensive, :popular]
end

我已经为每个带有分页的类别 (LIMIT 10) 实现了一个自定义 ORDER BY,所以当我获取产品列表时,我会在每个查询中获得多个 SQL 查询,其中 ORDER BY 不同,例如这个:

最近: SELECT "products".* FROM "products" ORDER BY "products"."created_at" DESC LIMIT 10

最便宜的:SELECT "products".* FROM "products" ORDER BY "products"."price" ASC LIMIT 10

最昂贵的: SELECT "products".* FROM "products" ORDER BY "products"."price" DESC LIMIT 10

受欢迎: SELECT "products".* FROM "products" ORDER BY "products"."popularity" DESC, "products"."created_at" DESC LIMIT 10

如上所述,上述每个查询的结果是 Product::ActiveRecord_Relation 包含 10 个产品,每个查询具有不同的顺序。

问题:

我已将新列添加到 Product 模型,它是带有布尔值的 featured,我需要在每个查询的开头应用 ORDER BY featured DESC,同时保持其他 ORDER BY 字段不变(即流行的查询应该是这样的SELECT "products".* FROM "products" ORDER BY "products"."featured" DESC, "products"."popularity" DESC, "products"."created_at" DESC LIMIT 10)。

注意: ORDER BY featured DESC 只是附加在前面的ORDER BY 语句的开头,它应用于子集而不是整个模型。

我尝试了什么?

我尝试了以下场景:

  • 在控制器中添加@products = @products.order(featured: :desc),但结果与预期不符,因为它将订单添加到现有订单链的末尾。
  • 在产品模型default_scope { order(featured: :desc) }中使用default_scope,但结果不是预期的,因为它在整个模型上实现了订单,但预期的结果是仅对子集(10条记录)应用订单。
  • 在控制器@products = @products.reorder('').order(featured: :desc) 中使用reorder,但结果仍然不如预期,因为这删除了旧订单,实际上我需要保留它,但在ORDER BY 链的末尾

我能做的唯一解决方案是使用字符串变量按链保存先前的订单,然后使用reorder('').order(featured: :desc),最后将字符串附加到新ORDER BY的末尾:

current_order = @products.to_sql[@products.to_sql.downcase.index('order by')+8..@products.to_sql.downcase.index('limit')-1]
@products = @products.reorder("featured desc, #{current_order}" )

但我确信有更好的解决方案需要您的支持才能实现。

总结:

正如下面的 cmets 中总结的,我需要以下实现:

仅给定r 其中r = M.order(:a),我想运行r.something(:b) 并获得M.order(:b).order(:a) 的效果,而不是r.order(:b) 会给你的M.order(:a).order(:b)

【问题讨论】:

  • 所以只给r 哪里r = M.order(:a) 你想说r.something(:b) 并得到M.order(:b).order(:a) 的效果而不是M.order(:a).order(:b) r.order(:b) 会给你的效果,对吧?
  • 由于只有 10 条记录,您也可以在 Ruby 中使用 @products.sort_by(&amp;:featured) 对它们进行排序,或者我是否误解了您想要的输出。
  • @Iceman sort_by 结果是数组,我期待 ActiveRecord_Relationsort_by 不适用于 boolean
  • 啊,好吧,只是一个想法,没有很好地阅读您的问题。

标签: ruby-on-rails ruby activerecord sql-order-by rails-activerecord


【解决方案1】:

您没有在这里使用scope 链接是否有原因?这似乎是使用它的完美案例。enum 的使用也不清楚。

类似这样的:

# /app/models/product.rb
class Product < ActiveRecord::Base
 scope :recent, { order(created_at: :desc) }
 scope :cheapest, { order(price: :asc) }
 scope :most_expensive, { order(price: :desc) }
 scope :popular, { order(popularity: :desc) }
 scope :featured, { where(featured: true) }
end

然后在你的控制器中你可以这样做:

# /app/controllers/products_controller.rb
...
Product.featured.cheapest.limit(10)
Product.featured.most_expensive.limit(10)
...

等等。

AREL 应该正确构建查询,如果您希望以不同方式应用它们,您可以在 IIRC 中交换范围的顺序(例如,cheapest 之后的featured)。

【讨论】:

  • 这对我的场景没有帮助,我的问题是关于修改 ORDER BY 链,并且需要在一个子集上实现(范围已经),我需要以通用方式进行(不是单独针对每个类别)。
  • 您可以查看@mu_is_too_short 评论,它以一种非常简单的方式总结了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多