У меня есть модель Card, которая имеет много CardSets, и модель 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
Я изменил класс расширения как 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?
как ложные, потому что обнаружил себя в базе данных. Я исправил это, добавив проверку для #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