2

我在Rails 4中構建了一個基於標記的論壇,其中主題可以與標記關聯。Rails:如何通過基於關聯或其他屬性的一個屬性有條件地應用ActiveRecord排序

class Topic < ActiveRecord::Base 
    ... 
    has_many :taggings, dependent: :destroy 
    has_many :tags, through: :taggings 
    ... 
    scope :sort_by_latest_message, -> { order(latest_message_at: :desc) } 
    scope :sort_by_sticky, -> { order(sticky: :desc) } 
    ... 
    scope :without_tags, -> { where.not(id: Tagging.select(:topic_id).uniq) } 
    scope :with_tags, -> { joins(:tags).where("tag_id IS NOT NULL").uniq } 
    ... 
end 

主題還有一個名爲「sticky」的布爾列。

問題:我希望能有話題,在該列表的頂部放置主題與粘性能的方式進行排序,但前提是該主題具有的至少一個關聯指定的標籤列表。然後主題將按照latest_message_at屬性進行排序。

這一切都發生在過濾過程之後。

因此,例如,主題列表將包含標籤X,Y和Z的主題,但只有標籤X的粘性主題應該被認爲是粘性的,因此任何具有粘性屬性但與標籤關聯的主題Y或Z而不是標籤X應該正常排序(通過最新消息)。因此,最終,列表頂部的標籤X下會有粘性主題(按最新消息排序),然後是標籤X下的所有其他主題以及標籤Y和Z下的主題,無論它們是否粘性,都按latest_message_at屬性排序。

目前,我有這樣的設置:

def self.combine_sort_with_sticky(tag_ids, primary_sort) 
    if tag_ids.empty? 
    relevent_sticky_topics = without_tags.where(sticky: true) 
    other_topics = union_scope(*[with_tags, without_tags.where(sticky: false)]) # union_scope is a method that creates an SQL union based on the scopes within 
    else 
    relevent_sticky_topics = joins(:tags).where("tag_id IN (?)", tag_ids).uniq.where(sticky: true) 
    other_topics = joins(:tags).where("tag_id NOT IN (?) OR sticky = ?", tag_ids, false).uniq 
    end 
    combined_topics = relevent_sticky_topics.send(primary_sort) + other_topics.send(primary_sort) # Order is important, otherwise stickies will be at the bottom. 
    combined_topics.uniq 
end 

所以,當我打電話combine_sort_with_sticky([1],:sort_by_latest_message),只有ID爲1的標籤和粘性能置頂主題被移到名單前面。我還會注意到,當不對任何標籤進行過濾時,只有沒有標籤的主題應該被認爲是粘性的。

這似乎給我想要的結果,但是這兩個有序查詢之間的+操作符讓我擔心,因爲它將ActiveRecord關聯轉換爲Array對象。

我在尋找的是一種在有條件地應用兩個排序範圍中的第一個時維護ActiveRecord關聯(如範圍或潛在的另一個類模型)的方法。 Topic.all.sort_by_sticky.sort_by_latest_message與我想要的很接近,但問題是它不分皁白地按粘性屬性進行排序,而不是僅將具有某些標籤的粘性主題視爲真正的粘性。

我一直在玩弄範圍如下所示:

scope :sort_by_relevant_sticky, ->(tag_ids) { joins(:tags).order("CASE WHEN tag_id IN (?) THEN sticky ELSE latest_message_at END DESC", tag_ids).uniq } 

,但似乎並不奏效。我不熟悉條件SQL。

我在production中的數據庫是Postgresql。

回答

相關問題