我有一个数组priority = ['HIGH', 'MEDIUM', 'LOW']
,用于设置'紧急'数据库列。我想检索按优先级排序的数据,但应用Task.order(:urgency)
会按字母顺序返回结果(即HIGH,LOW,MEDIUM)。
我正在使用PostgreSQL作为数据库。
我(显然)喜欢这些从高优先级返回到低优先级。有没有一种简单的方法来实现它,也许使用值在数组中的位置?
答案 0 :(得分:10)
一个简单的CASE WHEN
可以解决这个问题(这里使用的是postgreSQL语法):
scope :urgency_ordered {
order(<<-SQL)
CASE tasks.urgency
WHEN 'HIGH' THEN 'a'
WHEN 'MEDIUM' THEN 'b'
WHEN 'LOW' THEN 'c'
ELSE 'z'
END ASC,
id ASC
SQL
}
这样称呼:
Task.urgency_ordered
答案 1 :(得分:2)
如果使用Rails 4.1+,请考虑使用Active Record枚举(Release Notes和Documentation)作为数据库不可知解决方案:
class Task < ActiveRecord::Base
enum priority: [ :high, :medium, :low ]
# Or enum priority: { high: 0, medium: 1, low: 2 }
scope :priority_order, ->{ order(:priority) }
scope :reverse_priority_order, ->{ order(priority: :desc) }
end
这将需要一个新的整数列作为优先级,并将您拥有的文本数据复制/移动到新的整数列,这可以在迁移中完成。然后调用Task.priority_order
就可以了。
答案 2 :(得分:2)
现在已经很晚了,但这是我的2点。 (Rails 4.2.1)
如果您直接使用此解决方案:
class Task < ActiveRecord::Base
enum priority: { high: 0, medium: 1, low: 2 }
scope :priority_order, order(:priority)
end
您将收到此错误:The scope body needs to be callable.
您需要像这样调用范围。
scope :priority_order, -> {
order(:priority)
}
将其定义为Proc
或Lambda
。
为什么,你可能会问:)
确保每次触发范围时都使用块中的内容。
答案 3 :(得分:1)
我迟到了,但我很惊讶没有人提出这个答案:如果你使用MySQL(未经测试但也应该为Postgres工作),那么有一种更短,更安全,更通用的方式。任何以前的答案。它适用于任何字段并受到sql注入保护,因此您可以传递用户的任何值列表。
将以下范围添加到模型或ApplicationRecord:
class Task < ActiveRecord::Base
scope :order_by_field, ->(field, values) {
order(sanitize_sql_for_order(["field(#{field}, ?)", values]))
}
end
您现在可以直接在您的关系上调用范围:
tasks.ordered_by_field(:priority, ["high", "medium", "low"])