有一些型号具有has_many through
关联:
class Event < ActiveRecord::Base
has_many :event_categories
has_many :categories, through: :event_categories
validates :categories, presence: true
end
class EventCategory < ActiveRecord::Base
belongs_to :event
belongs_to :category
validates_presence_of :event, :category
end
class Category < ActiveRecord::Base
has_many :event_categories
has_many :events, through: :event_categories
end
问题在于分配event.categories = []
-它会立即从event_categories
中删除行因此,以前的关联将被不可逆转地破坏,事件将失效。
在has_many, through:
的情况下,如何验证记录的存在?
UPD:在回答之前,请仔细阅读粗体标记的句子。轨道4.2.1
您必须创建一个自定义验证,如下所示:
validate :has_categories
def has_categories
unless categories.size > 0
errors.add(:base, "There are no categories")
end
end
这向你展示了总体思路,你可以根据自己的需求进行调整。
更新
这篇文章又出现了,我找到了填补空白的方法。
验证可以保持如上所述。除此之外,我要补充的是直接分配一组空类别的情况。那么,我该怎么做呢?
想法很简单:重写setter方法以不接受空数组:
def categories=(value)
if value.empty?
puts "Categories cannot be blank"
else
super(value)
end
end
这将适用于每个赋值,除非赋值为空集。然后,什么都不会发生。不会记录任何错误,也不会执行任何操作。
如果你还想添加一条错误消息,你必须即兴发挥。为类添加一个属性,该属性将在铃声响起时填充。所以,长话短说,这个模型对我有效:
class Event < ActiveRecord::Base
has_many :event_categories
has_many :categories, through: :event_categories
attr_accessor :categories_validator # The bell
validates :categories, presence: true
validate :check_for_categories_validator # Has the bell rung?
def categories=(value)
if value.empty?
self.categories_validator = true # Ring that bell!!!
else
super(value) # No bell, just do what you have to do
end
end
private
def check_for_categories_validator
self.errors.add(:categories, "can't be blank") if self.categories_validator == true
end
end
在添加了最后一次验证后,如果您这样做,实例将无效:
event.categories = []
但是,不会执行任何操作(跳过更新)。
使用validates_associated
,官方文档在这里
如果您使用RSpec作为测试框架,请查看Shoulda Matcher。这里有一个例子:
describe Event do
it { should have_many(:categories).through(:event_categories) }
end