0

だから私はこれらの2つのモデルを持っています:

class Tag < ActiveRecord::Base
has_many :event_tags
attr_accessible :tag_id, :tag_type, :value
end

class EventTag < ActiveRecord::Base
belongs_to :tag
attr_accessible :tag_id, :event_id, :region
end

とタグのこのテーブル:

**tag_id**    **tag_type**      **value**
    1         "funLevel"        "Boring..."
    2         "funLevel"        "A Little"
    3         "funLevel"        "Hellz ya"

    4         "generic"         "Needs less clowns"
    5         "generic"         "Lazer Tag"
    ...

私がやりたいのは、次のことを確認するカスタム検証を作成することです。

  • 各event_idには、「funLevel」のtag_typeが1つだけ添付されていますが、複数の「generic」タグを含めることができます

例えば:

t1 = EventTag.new(:tag_id => 1, :event_id =>777, :region => 'US')
t1.save  # success

t2 = EventTag.new(:tag_id => 2, :event_id =>777, :region => 'US')
t2.save  # failure 
         # because (event_id: 777) already has a tag_type of 
         # "funLevel" associated with it

t3 = EventTag.new(:tag_id => 4, :event_id =>777, :region => 'US')
t3.save  # success, because as (tag_id:4) is not "funLevel" type

私は1つの醜い解決策を思いついた:

def cannot_have_multiple_funLevel_tag
  list_of_tag_ids = EventTag.where("event_id = ?", event_id).pluck(:tag_id)
  if(Tag.where("tag_id in ?", list_of_tag_ids).pluck(:tag_type).include? "funLevel")
    errors.add(:tag_id, "Already has a Fun Level Tag!")
end

Railsを初めて使用する場合、より優れた/よりエレガントな/より安価な方法はありますか?

4

1 に答える 1

0

データを構造化する方法は、組み込みのRails検証がおそらくあなたの助けになることはないということを意味します。クラスが属性に直接アクセスできる場合は、次のように使用できます。funLevelEventTag

# event_tag.rb
validate :tag_type, uniqueness: { scope: :event_id },
    if: Proc.new { |tag| tag.tag_type == "funLevel" }

(残念ながら、簡単なテストでは、仮想属性の一意性を検証できないようです。)

それがないと、カスタム検証を使用してスタックしている可能性があります。あなたが持っているカスタム検証への明らかな改善は(あなたが検証をしたいように見えるならば)それがタグEventTagでない限り検証を実行しないことです:EventTagfunLevel

def cannot_have_multiple_funLevel_tag
  return unless self.tag.tag_type == "funLevel"
  ...
end
于 2013-03-20T23:53:41.417 に答える