Rails - 列值的排序(优先级列)

时间:2015-04-21 14:43:36

标签: sql ruby-on-rails postgresql

我有一个数组priority = ['HIGH', 'MEDIUM', 'LOW'],用于设置'紧急'数据库列。我想检索按优先级排序的数据,但应用Task.order(:urgency)会按字母顺序返回结果(即HIGH,LOW,MEDIUM)。

我正在使用PostgreSQL作为数据库。

我(显然)喜欢这些从高优先级返回到低优先级。有没有一种简单的方法来实现它,也许使用值在数组中的位置?

4 个答案:

答案 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 NotesDocumentation)作为数据库不可知解决方案:

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)
}

将其定义为ProcLambda

为什么,你可能会问:)

确保每次触发范围时都使用块中的内容。

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