使用单表继承验证多个子类之间的唯一性 [英] validate uniqueness amongst multiple subclasses with Single Table Inheritance
问题描述
我有一个具有许多 CardSet 的 Card 模型和一个通过 Membership 模型具有许多 Cards 的 CardSet 模型:
I have a Card model that has many CardSets and a CardSet model that has many Cards through a Membership model:
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
我也有一些上面使用单表继承的子类:
I also have some sub-classes of the above using Single Table Inheritance:
class FooCard < Card
end
class BarCard < Card
end
和
class Expansion < CardSet
end
class GameSet < CardSet
validates_size_of :cards, :is => 10
end
以上所有内容都按我的意图工作.我想弄清楚的是如何验证卡只能属于一个扩展.我希望以下内容无效:
All of the above is working as I intend. What I'm trying to figure out is how to validate that a Card can only belong to a single Expansion. I want the following to be invalid:
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**
但是,游戏集应该允许这种行为:
However, GameSets should allow this behavior:
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 调用,但我不确定把它放在哪里.有什么建议吗?
I'm guessing that a validates_uniqueness_of call is needed somewhere, but I'm not sure where to put it. Any suggestions?
我按照建议修改了扩展类:
I modified the Expansion class as 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.!
我说话有点太快了.上述解决方案运行良好,直到我使用新卡更新扩展.它错误地将后续的 #valid?
检查识别为 false,因为它在数据库中发现了自己.我通过在验证方法中添加对 #new_record?
的检查来解决此问题:
I spoke a little too soon. The above solution was working great until I went to update an Expansion with a new card. It was incorrectly identifying subsequent #valid?
checks as false because it was finding itself in the database. I fixed this by adding a check for #new_record?
in the validation method:
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
推荐答案
我真的不确定这一点,我只是在尝试,因为我无法在这里进行测试... 但也许像下面这样的东西适合你.让我知道是否有:]
I'm really not sure about that, I'm just trying because I'm not able to test it here... but maybe something like the following works for you. Let me know if it does :]
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
这篇关于使用单表继承验证多个子类之间的唯一性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!