我正在研究三种模式关系,其中一方面我不确定如何处理。这是基本关系:
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
,然后只能从给定照片附加的分类中选择一个术语。现在,Photo可能会应用多个分类。例如:
分类:颜色,包容性 术语:红色(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。
这有意义吗?
答案 0 :(得分: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