0

多くのCardSetを含むCardモデルと、メンバーシップモデルを介して多くのCardを含むCardSetモデルがあります。

class Card < ActiveRecord::Base
  has_many :memberships
  has_many :card_sets, :through => :memberships
end

class Membership < ActiveRecord::Base
  belongs_to :card
  belongs_to :card_set

  validates_uniqueness_of :card_id, :scope => :card_set_id
end

class CardSet < ActiveRecord::Base
  has_many :memberships
  has_many :cards, :through => :memberships

  validates_presence_of :cards
end

また、単一テーブル継承を使用した上記のサブクラスもいくつかあります。

class FooCard < Card
end

class BarCard < Card
end

class Expansion < CardSet
end

class GameSet < CardSet
  validates_size_of :cards, :is => 10
end

上記のすべてが私が意図したように機能しています。私が理解しようとしているのは、カードが単一の拡張にのみ属することができることを検証する方法です。以下を無効にしたい:

some_cards = FooCard.all( :limit => 25 )

first_expansion = Expansion.new
second_expansion = Expansion.new

first_expansion.cards = some_cards
second_expansion.cards = some_cards

first_expansion.save    # Valid
second_expansion.save   # **Should be invalid**

ただし、GameSetsはこの動作を許可する必要があります。

other_cards = FooCard.all( :limit => 10 )

first_set = GameSet.new
second_set = GameSet.new

first_set.cards = other_cards    # Valid
second_set.cards = other_cards   # Also valid

どこかにvalidates_uniqueness_of呼び出しが必要だと思いますが、どこに置くかわかりません。助言がありますか?

更新1

私はExpansionクラスをsugestedとして変更しました:

class Expansion < CardSet 
  validate :validates_uniqueness_of_cards

  def validates_uniqueness_of_cards
    membership = Membership.find(
      :first,
      :include => :card_set,
      :conditions => [
        "card_id IN (?) AND card_sets.type = ?",
        self.cards.map(&:id), "Expansion"
      ]
    )
    errors.add_to_base("a Card can only belong to a single Expansion") unless membership.nil?
  end
end

これはうまくいきます!ありがとうJ.!

アップデート2

私は少し早すぎた。上記のソリューションは、拡張機能を新しいカードで更新するまではうまく機能していました。#valid?データベースで自分自身を見つけていたため、後続のチェックを誤ってfalseとして識別していました。#new_record?検証メソッドにチェックを追加することで、これを修正しました。

class Expansion < CardSet
  validate :validates_uniqueness_of_cards

  def validates_uniqueness_of_cards
    sql_string = "card_id IN (?) AND card_sets.type = ?"
    sql_params = [self.cards.map(&:id), "Expansion"]

    unless new_record?
      sql_string << " AND card_set_id <> ?"
      sql_params << self.id
    end

    membership = Membership.find(
                   :first,
                   :include => :card_set,
                   :conditions => [sql_string, *sql_params]
                 )

    errors.add_to_base("a Card can only belong to a single Expansion") unless membership.nil?
end
4

2 に答える 2

1

私はそれについて本当によくわかりません、私はここでそれをテストすることができないので私はただ試みています...しかし多分次のような何かがあなたのために働きます。もしそうなら私に知らせてください:]

class Expansion < Set 
   validate :validates_uniqueness_of_cards

   def validates_uniqueness_of_cards
      membership = Membership.find(:first, :include => :set,
         :conditions => ["card_id IN (?) AND set.type = ?",
            self.cards.map(&:id), "Expansion"])
      errors.add_to_base("Error message") unless membership.nil?
   end
end
于 2010-06-10T23:11:10.853 に答える
1

ここでのパーティーには非常に遅れていますが、STIを設定していると仮定すると、stiタイプにスコープされた属性の一意性を検証できるようになります。

例えば

validates_uniqueness_of:your_attribute_id、scope::type

于 2019-07-18T10:41:21.237 に答える