class Promotion < ActiveRecord::Base
has_many :promotion_sweepstakes,
has_many :sweepstakes,
:through => :promotion_sweepstakes
end
class PromotionSweepstake < ActiveRecord::Base
belongs_to :promotion
belongs_to :sweepstake
end
class Sweepstake < ActiveRecord::Base
# Not relevant in this question, but I included the class
end
所以通过联盟表PromotionSweepstake促销有很多抽奖活动。这是一个遗留的数据库模式,所以命名可能看起来有点奇怪,并且有一些self.table_name ==和foreign_key的东西被遗漏了。
此应用的性质要求,对于promotionId,联接表中至少有一个条目,因为没有抽奖活动会破坏应用。
我如何保证PromotionSweepstake中始终有一个条目可用于促销?创建时必须至少包含一个Sweepstake.id,一旦创建了连接表中的条目,必须至少为每个Promotion / promotion_id 一个。
如果之前的建议无法实现,我怀疑是否属实,那么可以通过另一种方式解决问题。有一种具有特定id的“默认Sweepstake”。如果通过表单将删除所有sweepstake_ids(以便删除连接表中促销的所有条目),我可以在PromotionSweepstake中创建新条目吗?
使用ids [1,4,5]删除promotion_sweepstake,其中promotion_id = 1 如果id = 1的促销没有promotion_sweepstakes 使用promotion_id 1和sweepstake_id 100添加promotion_sweepstake 端
感谢您的帮助。
答案 0 :(得分:1)
在创建和修改促销活动时,状态验证应解决问题。
class Promotion < ActiveRecord::Base
has_many :promotion_sweepstakes
has_many :sweepstakes,
:through => :promotion_sweepstakes
validates :sweepstakes, :presence => true
end
为了确保在尝试删除或更新Sweepstake或PromotionSweepstake时保持一致性,您必须为这两个类编写自己的验证。他们必须检查先前引用的促销是否仍然有效,即仍然有一些抽奖活动。
一个简单的解决方案将在validates :sweepstakes, :presence => true
中占据Promotion
的优势。在事务中更新引用的PromotionSweepstakes或Sweepstakes之后,您必须在之前引用的Promotions上调用Promotion#valid?
。如果它们无效,则会回滚事务,因为修改会破坏一致性。
或者,您可以在PromotionSweepstake和Sweepstake中使用before_destroy
,以防止更改违反您的一致性要求。
class PromotionSweepstake < ActiveRecord::Base
belongs_to :promotion
belongs_to :sweepstake
before_destroy :check_for_promotion_on_destroy
private
def check_for_promotion_on_destroy
raise 'deleting the last sweepstake' if promotion.sweepstakes.count == 1
end
end
class Sweepstake < ActiveRecord::Base
has_many :promotion_sweepstakes
has_many :promotions, :through => :promotion_sweepstakes
before_destroy :check_for_promotions_on_destroy
private
def check_for_promotions_on_destroy
promotions.each do |prom|
raise 'deleting the last sweepstake' if prom.sweepstakes.count == 1
end
end
end