我有一個數組priority = ['HIGH', 'MEDIUM', 'LOW']
,它用於設置'緊急'數據庫列。我想檢索按優先級排序的數據,但應用Task.order(:urgency)
可以按字母順序返回結果(即高,低,中等)。Rails - 按列的值排序(優先列)
我正在使用PostgreSQL作爲數據庫。
我會(顯然)像這些從高優先級返回到低優先級。有沒有簡單的方法來實現這個,也許使用數組中的值的位置?
我有一個數組priority = ['HIGH', 'MEDIUM', 'LOW']
,它用於設置'緊急'數據庫列。我想檢索按優先級排序的數據,但應用Task.order(:urgency)
可以按字母順序返回結果(即高,低,中等)。Rails - 按列的值排序(優先列)
我正在使用PostgreSQL作爲數據庫。
我會(顯然)像這些從高優先級返回到低優先級。有沒有簡單的方法來實現這個,也許使用數組中的值的位置?
簡單CASE WHEN
可以做的伎倆(這裏使用PostgreSQL的語法):
scope :urgency_ordered, order("CASE tasks.urgency WHEN 'HIGH' THEN 'a' WHEN 'MEDIUM' THEN 'b' WHEN 'LOW' THEN 'c' ELSE 'z' END ASC, id ASC")
這樣調用它:
:Task.urgency_ordered
的SQL CASE WHEN
的尼斯輸出
CASE tasks.urgency
WHEN 'HIGH' THEN 'a'
WHEN 'MEDIUM' THEN 'b'
WHEN 'LOW' THEN 'c'
ELSE 'z'
END ASC, id ASC
發揮魅力 - 感謝MrYoshiji先生!我必須把我的範圍包裝在一個lambda中,例如'scope:urgency_ordered, - > {order(「CASE tasks.urgency'HIGH','''' 'MEDIUM'then'b''LOW'那麼'c'ELSE'z' END ASC,id ASC「)}'(以防其他人需要以相同的方式使用它),但它完美地完成了這項工作! – SRack
您不需要使用lambda表達式:只有當您需要動態值時才需要使用lambda表達式,例如'Date.today'或'user'參數(因爲範圍的結果取決於變量)。在這裏,就你的情況而言,order子句不依賴於一個變量,它總是與任務被排序的方式相同。 – MrYoshiji
啊,很有道理。我做這個改變的原因是我得到了一個'範圍體需要被調用。'沒有它的錯誤,並且有一點Google會告訴我lambda會修復它。它在這種情況下做到了 - 雖然你的理由對我很有意義。爲了我自己的好奇,你知道這可能是爲什麼嗎? (不要擔心,如果不是,我的問題畢竟解決了!) – SRack
如果使用Rails 4.1或更高版本,可以考慮使用的Active Record枚舉(Release Notes和Documentation)爲DB無關的解決方案:
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
應該做的伎倆。
這看起來是一個很好的解決方案。如果我可以標出兩個答案......感謝您的意見,我一定會在將來記住這一點! – SRack
Np,MrYoshiji的回答是一個很好的答案 - 它應該適用於任何版本的Rails,並且不需要更改模型代碼和/或視圖的其他部分。如果你足夠幸運能夠使用4.1+,我喜歡使用枚舉特性。如果您決定在未來走這條路線,我可以發佈遷移 - 我只需要一些關於您現有代碼的更多細節(不要破壞現有功能)。 – marksiemers
這是遲到了,但在這裏我的2cents。
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.
你需要調用這樣的範圍如果直接使用該解決方案是這樣的(Rails的4.2.1)
。
scope :priority_order, -> {
order(:priority)
}
定義它像Proc
或Lambda
。
爲什麼,你可能會問:)
它可以確保你有什麼塊中的每個範圍被觸發時使用。
好,如果我建議使用Rails 4.1+功能,我想我應該提供Rails 4.0+兼容範圍! – marksiemers
我遲到了,但我很驚訝沒有人想出這個答案呢:如果你正在使用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"])
什麼DB系統是您使用? MySQL? PostgreSQL?還有別的嗎? – MrYoshiji
PostgreSQL - 對不起,應該提到。現在更新! – SRack
這並不直接回答您的訂購問題,但對於「緊急」或「狀態」,如果您使用的是Rails 4.1+,請考慮使用Active Record枚舉([發行說明](http://guides.rubyonrails.org/) 4_1_release_notes.html#active-record-enums)和[Documentation](http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html))。優點是它爲您提供了免費的範圍,並且可以按照您需要的順序(實際的數據庫列是一個整數)放置您的「緊迫性」 - 您可以基於該數據進行排序,這應該比SQL執行速度快很多CASE聲明。如果需要,我可以提供一個完整的示例。 – marksiemers