1

我正在研究一种三模型关系,其中一个方面我不确定如何处理。基本关系如下:

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 :through 不能工作,因为术语是照片的习惯,所以如果有人知道建立这种关系的更优雅的方式,我很想听听。

谢谢!


更新,进一步解释分类思想:

如果分类是exclusiveie。taxonomy.inclusive = false,则该分类中只能有一个术语附加到给定照片上。现在,一张照片可能应用了多个分类。例如:

分类:颜色,包含术语:红色 (id 1)、蓝色 (id 2)、绿色 (id 3)

分类:地区、专有术语:北美 (id 4)、南美 (id 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。

那有意义吗?

4

1 回答 1

2

对于您的验证问题,您可以在Term模型的taxonomy_id字段上添加唯一性验证,该验证仅在分类法不包含在内时才执行,即:

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

您也可以使用自定义验证方法执行此操作:

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 约定,它实际上是 table 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
于 2012-11-12T07:03:47.053 回答