我有一个Card模型,它有许多CardSet和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**
但是,GameSet应该允许这种行为:
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调用,但我不知道该把它放到哪里。有什么建议吗?
我将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。!
我说得太早了。上述解决方案运行良好,直到我用新卡更新扩展。它错误地将后续#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
答案 0 :(得分: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
答案 1 :(得分:0)
在这里参加聚会很晚,但是假设您已经设置了STI,那么您现在就可以验证范围为sti类型的属性的唯一性,
例如
validates_uniqueness_of:您的属性ID,范围::类型