проверить уникальность среди нескольких подклассов с наследованием одной таблицы - PullRequest
0 голосов
/ 11 июня 2010

У меня есть модель 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

1 Ответ

1 голос
/ 11 июня 2010

Я на самом деле не уверен в этом, я просто пытаюсь, потому что я не могу проверить это здесь ... но, возможно, что-то вроде следующего работает для вас.Дайте мне знать, если это так:]

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
...