ruby-on-rails - 更改 ActiveRecord 子集上的 'ORDER BY' 链

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

背景:

我有 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

most_expensive: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 模型中,该模型具有 bool 值 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语句的开头,应用于子集不是在整个模型上。

我尝试了什么?

我尝试过以下场景:

  • 在 Controller 中添加 @products = @products.order(featured: :desc) 但结果不符合预期,因为它通过链将订单添加到现有订单的末尾。<
  • 在 Product 模型 default_scope { order(featured: :desc) } 中使用 default_scope 但结果不如预期,因为它在整个模型上实现了顺序,但是预期结果是仅在子集(10 条记录)上应用顺序。
  • 在 Controller 中使用 reorder @products = @products.reorder('').order(featured: :desc) 但结果仍然不如预期,因为这删除旧订单,实际上我需要保留它,但在 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}" )

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

总结:

正如下面评论中总结的那样,我需要以下实现:

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

最佳答案

您在这里没有使用 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

然后在你的 Controller 中你可以做:

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

等等。

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

关于ruby-on-rails - 更改 ActiveRecord 子集上的 'ORDER BY' 链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42664738/

相关文章:

ruby-on-rails - Assets 管道中的条件 javascript require

ruby-on-rails - Ruby on Rails : found unpermitted parameters: _method, 真实性_token

ruby-on-rails - 在 Rails View 中创建拖放表的更好方法是什么?

ruby-on-rails - 检查一个项目是否在另一个模型的 `has_many` 字段中的最简单方法?

ruby-on-rails - Rails 不会为 fixture 生成 created_at

mysql - 尝试部署 Rails 应用程序时,使用 MySql 时出现重复列名错误

ruby-on-rails - Rails 通过资源实现的默认路由

ruby - Ruby 书中的代码块

mysql - 计算具有不同列的行数

ruby-on-rails - 在 Rails 中使用 Postgres UUID 时破坏了加入记录的创建、保存、更新和销毁