2012-11-12 58 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