基于枚举值的自定义顺序

时间:2016-06-02 18:26:21

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

我为角色定义了枚举:

enum role: {ordinary: 0, manager: 1, admin: 2}

我希望按以下顺序订购一组对象:

admin (first all admins)
ordinary (then all ordinaries)
manager (and lastly all managers)

这有可能吗?

3 个答案:

答案 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
         )

this

的好参考资料

答案 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