2012-11-12 104 views
1

我正在處理三個模型的關係,我不知道如何處理一個方面。這裏的基本關係:Rails驗證三個模型之間的關係

class Taxonomy 
    has_many :terms 
    # attribute: `inclusive`, default => false 
end 

class Term 
    belongs_to :taxonomy 
    has_and_belongs_to_many :photos 
end 

class Photo 
    has_and_belongs_to_many :terms 
end 

這是唯一不同的是很簡單的東西:

的分類法可以是「包容性」或「獨佔」。獨家表示這些條款是相互排斥的,包含意味着它們不是。

現在,我可以在客戶端沒有問題地處理這個問題,但是我不太確定如何在照片(或其他地方)上設置基本驗證的驗證:「驗證不超過一個術語來自獨家分類與此記錄相關聯。「

獎金問題

此外,雖然它不是必需的,我一直在想這將是很好設置一個加入某種分類和照片,即之間的,我想一個簡單的方法查詢已經按照給定分類術語分類的所有照片。

我想我可以用Photo.where('term_id in ?', Taxonomy.find(1).terms.map(&:id))之類的東西做到這一點,但顯然這不是很優雅。我非常確定has_many:通過無法工作,因爲條款對照片是有害的,所以如果有人知道建立這種關係的更優雅的方式,我很樂意聽到它。

謝謝!


更新,進一步解釋了分類的想法:

如果分類是exclusive即。 taxonomy.inclusive = false,那麼附加到給定照片的分類法只能有一個術語。現在,一張照片可能會應用多種分類法。例如:

分類:顏色,包容 條款:紅(ID 1),藍(ID 2),綠(ID 3)

分類:地區,獨家 條款:北美(ID 4) ,南美洲(編號5)

因此,假設我們有一張照片,裏面有很多紅色和藍色的照片,所以它得到了這兩個詞,它可能在南美洲,所以它得到了這個詞。但是,一張照片不能同時在北美和南美。因此,在這種情況下

如果我們稱之爲:photo.terms.map &:id我們會得到[1,2,4]

在客戶端,我基本上可以做到(僞代碼)

form_for photo 
- Taxonomy.each do |tax| 
    - if tax.inclusive? 
    - tax.terms.each do |term| 
     - check_box term 
    - else 
    - tax.terms.each do |term| 
     - radio_button term 

但在模型方面,我想例如,一張照片可以有任何term_id 1,2,3,但只有其中一個/或4和5.

這是否合理?

回答

2

爲了您的驗證問題,您可以在Term模型添加唯一性驗證的taxonomy_id字段,只執行,如果分類不包容,即:

class Term 
    validates :taxonomy_id, uniqueness: true, unless: Proc.new { |term| term.taxonomy.inclusive } 
end 

你也可以用custom validation method做到這一點:

class Term 
    validate :uniqueness_of_taxonomy_if_exclusive 

    def uniqueness_of_taxonomy_if_exclusive 
    if !taxonomy.inclusive && Term.find_by_taxonomy_id(taxonomy_id) 
     errors.add(:taxonomy_id, "already exists for this exclusive taxonomy") 
    end 
    end 
end 

注意,這是在這種情況下沒用,因爲第一種方法產生相同的結果,但如果你有更復雜的驗證做可能是有用的。

對於你的問題的第二部分,這裏是使ActiveRecord的查詢方式,讓我們假設taxonomy是您想要的照片分類:

Photo.includes(:terms => :taxonomy).where('taxonomies.id' => taxonomy.id) 

更新您的評論

我相信你的驗證應該發生在使照片和術語之間關聯的表格中。如果你有下面的Rails約定,它實際上是表photos_terms。 要爲其添加驗證,您必須將其設爲第一級公民,即:爲此表添加活動記錄模型和ID字段,假設您將其命名爲PhotoTermLink。 以下是您要驗證的代碼:

class PhotoTermLink 
    belongs_to :photo 
    belongs_to :term 

    validates :term_id, uniqueness: { scope: :photo_id }, unless: Proc.new { |link| link.term.taxonomy.inclusive } 
end 
+0

Adrien,謝謝!要明確一點:可以有多個術語作爲(屬於)「獨家」分類法的一部分,只有其中一個術語應與照片相關聯。那麼,你所描述的驗證是否覆蓋了這一點?在我看來,它會將「排他性」分類法限制爲一個術語,而不是將照片限定爲「專屬」分類法中的一個術語。 – Andrew

+0

對不起,我誤解了你的需求,但我只是用你想要的驗證更新了我的答案。 –

+0

好吧,剩下的一個問題,照片可以有很多條款,因爲它可以有來自多個分類標準的術語,所以我不能將分類術委託給術語,因爲它是一種習慣......我正在更新問題來說明我認爲這是造成大部分併發症的原因... – Andrew