我为角色定义了枚举:
enum role: {ordinary: 0, manager: 1, admin: 2}
我希望按以下顺序订购一组对象:
admin (first all admins)
ordinary (then all ordinaries)
manager (and lastly all managers)
这有可能吗?
答案 0 :(得分:11)
解决方案:
class YourModel < ActiveRecord::Base
ROLE_ORDERS = [2, 0, 1]
scope :order_by_role, -> {
order_by = ['CASE']
ROLE_ORDERS.each_with_index do |role, index|
order_by << "WHEN role=#{role} THEN #{index}"
end
order_by << 'END'
order(order_by.join(' '))
}
end
然后你的查询会很简单:
YourModel.order_by_role
生成的查询是:
SELECT * from your_models
ORDER BY ( CASE
WHEN role=2 THEN 0
WHEN role=0 THEN 1
WHEN role=1 then 2
END
)
的好参考资料
答案 1 :(得分:2)
感谢this answer我想出了这个:
order("role = 0 DESC, role = 1 DESC, role = 2 DESC")
或者,作为带有可选参数的范围:
scope :order_by_roles, -> (first = :admin, second = :ordinary, third = :manager) {
order("role = #{User.roles[first]} DESC, role = #{User.roles[second]} DESC, role = #{User.roles[third]} DESC")
}
答案 2 :(得分:2)
从@hieu-pham's solution开始使用Rails 6.0,将引发以下弃用警告:“使用非属性参数[..]调用的危险查询方法(其参数用作原始SQL的方法)在Rails 6.1中是不允许的。不应使用用户提供的值(例如请求参数或模型属性)调用此方法。可以通过将已知的安全值包装在Arel.sql()中来传递该值。”
因此,根据他的答案和@fellow-stranger's,我建议这样做:
class YourModel < ActiveRecord::Base
ROLE_ORDERS = [2, 0, 1]
scope :order_by_role, -> { order(Arel.sql(ROLE_ORDERS.map{ |role| "role=#{role} DESC" }.join(', '))) }
end
然后将其用在您的代码中,就像@hieu-pham's solution ...
YourModel.order_by_role
...生成此查询:
SELECT * from your_models
ORDER BY role = 2 DESC, role = 0 DESC, role = 1 DESC