ruby或rails是否提供了按指定顺序排序字符串的方法?假设我有以下优先级:“严重,高,中,低”。
这些优先事项不会经常变化(如果有的话)。我有一个带优先级列的任务模型:
tasks
- id (integer)
- name (string)
- priority (string)
我想获得按优先级排序的所有任务的数组。由于逻辑顺序不遵循字母顺序,因此不可能只按优先级顺序排序:
Task.all(:order => :priority)
我所做的是创建优先级模型并定义关联:任务belongs_to优先级。在优先级表中,然后我为每个优先级名称分配了一个值并按该值排序。有一个更好的方法吗?我宁愿没有优先级表并声明PRIORITY常量(作为哈希),或者只是在任务表中将优先级指定为字符串。
答案 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)
我选择这种方法是因为
这种做法可能不够灵活,但我也是,我尽量不把这个问题概括为一般,除非有必要
答案 6 :(得分:1)
我建议使用acts_as_list(http://github.com/rails/acts_as_list/tree/master),它会在你的对象中添加一个位置字段,但同时也会为你提供所有在列表中上下移动内容的方法,同时保留正确的顺序。
如果优先级永远不会改变,那么在任务表上优先考虑一个字段可能会更好。问题是您需要能够按优先级排序。为此您有几个选项,但无论您选择什么,都应该由db。
完成