Rails:记录的自定义顺序

时间:2009-08-30 13:54:49

标签: ruby-on-rails

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

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

tasks
  - id (integer)
  - name (string)
  - priority (string)

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

Task.all(:order => :priority)

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

7 个答案:

答案 0 :(得分: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

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

Task.all.by_priority

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

答案 1 :(得分: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) }

答案 2 :(得分:5)

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

答案 3 :(得分:4)

切换到像Aaron这样的整数,然后你可能想要使用default_scope

例如:

class Task < ActiveRecord::Base
  default_scope :order => 'tasks.position' # assuming the column name is position
  ...

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

答案 4 :(得分:4)

如果不能选择更改架构以使用整数优先级,则还可以定义自定义&lt; =&gt;任务定义排序顺序的方法。

class Task

  PRIORITIES = {
    :high => 3,
    :med  => 2,
    :low  => 1,
  }

  def <=> (other)
    PRIORITIES[self.priority] <=> PRIORITIES[other.priority]
  end

end

这样做的缺点是你需要在Ruby方面进行排序,而不是让你的数据库为你做,这将排除使用default_scope。好处是,只要您在任务数组上调用sort,订单就会正确显示(或者,如果您只想在某个特定位置进行自定义排序,则可以使用sort_by)。< / p>

答案 5 :(得分:2)

只是为了解决您的具体问题:您可以通过最后一封信来订购。

  

Sever(e),Hig(h),Mediu(m),Lo(w)

你可以在rails或sql中执行:

order by RIGHT(priority, 1)

我选择这种方法是因为

  1. 这是最简单的方法。
  2. 你提到它不会改变。
  3. 这种做法可能不够灵活,但我也是,我尽量不把这个问题概括为一般,除非有必要

答案 6 :(得分:1)

我建议使用acts_as_list(http://github.com/rails/acts_as_list/tree/master),它会在你的对象中添加一个位置字段,但同时也会为你提供所有在列表中上下移动内容的方法,同时保留正确的顺序。

如果优先级永远不会改变,那么在任务表上优先考虑一个字段可能会更好。问题是您需要能够按优先级排序。为此您有几个选项,但无论您选择什么,都应该由db。

完成