Rails:记录的自定义顺序

Hom*_*mar 21 ruby-on-rails

ruby或rails是否提供了按指定顺序排序字符串的方法?假设我有以下优先级"严重,高,中,低".

这些优先事项不会经常变化(如果有的话).我有一个优先级列的任务模型:

tasks
  - id (integer)
  - name (string)
  - priority (string)
Run Code Online (Sandbox Code Playgroud)

我想获得按优先级排序的所有任务的数组.由于逻辑顺序不遵循字母顺序,因此无法按优先级顺序排序:

Task.all(:order => :priority)
Run Code Online (Sandbox Code Playgroud)

我所做的是创建优先级模型并定义关联:任务belongs_to优先级.在优先级表中,然后我为每个优先级名称分配了一个值并按该值排序.有一个更好的方法吗?我宁愿没有优先级表并声明PRIORITY常量(作为哈希),或者只是在task表中将优先级指定为字符串.

Evi*_*out 26

您可以在where子句中使用case语句.这有点难看,但应该工作:

class Task
  PRIORITIES_ORDERED = ['high', 'medium', 'low']

  # Returns a case statement for ordering by a particular set of strings
  # Note that the SQL is built by hand and therefore injection is possible,
  # however since we're declaring the priorities in a constant above it's
  # safe.
  def self.order_by_case
    ret = "CASE"
    PRIORITIES_ORDERED.each_with_index do |p, i|
      ret << " WHEN priority = '#{p}' THEN #{i}"
    end
    ret << " END"
  end

  named_scope :by_priority, :order => order_by_case

end
Run Code Online (Sandbox Code Playgroud)

然后,当您希望按优先级排序时,您可以执行以下操作:

Task.all.by_priority
Run Code Online (Sandbox Code Playgroud)

当然,正如其他人所提到的,为Priority表而不是文本字符串列创建外键更为清晰.在Priorty表中,您可以将位置列添加为可以排序的整数,并且存在插件以使其更容易.

  • 谢谢你完美的工作,但我不得不将"named_scope"改为"范围" (2认同)

tma*_*314 13

这是更新版本,适用于rails 4.1和一些自定义:

  PRIORITIES_ORDERED = ['Unknown', 'Critical', 'Warning', 'Ok']
  def self.order_by_case
    ret = "CASE"
    PRIORITIES_ORDERED.each_with_index do |p, i|
      ret << " WHEN status = '#{p}' THEN #{i}"
    end
    ret << " END"
  end

  scope :order_by_priority, -> { order(order_by_case) }
Run Code Online (Sandbox Code Playgroud)

  • 只是一个可能有帮助的澄清(对我来说是这样)。您可以像这样扩展排序:scope :order_by_priority, -&gt; { order(order_by_case, "updated_at desc") } 这让我们按优先级排序,然后按每个优先级的最后更新排序。 (2认同)

joh*_*nja 8

这是 Rails 7 的更新版本:

Task.in_order_of(:priority, %w[Severe High Medium Low])
Run Code Online (Sandbox Code Playgroud)

介绍它的文档PR + 讨论


Aar*_*ian 5

我会在db中使用整数.排序和索引更容易,然后覆盖属性getter和setter以使用符号进行外部接口.


And*_*ell 4

像 Aaron 所说的那样切换到整数,那么您可能会想要使用default_scope

例如:

class Task < ActiveRecord::Base
  default_scope :order => 'tasks.position' # assuming the column name is position
  ...
Run Code Online (Sandbox Code Playgroud)

使用默认范围,您不必在任何查找方法调用中指定排序顺序 - 任务将自动排序。