我正在试图弄清楚如何做这样的事情:
event = Event.new
loc = Location.new
loc.name = "test"
loc.save
event.locations << loc
event.save!
事件和位置有多对多的关系。但是,我一直收到这个错误:
ActiveRecord::RecordInvalid: Validation failed: Event locations is invalid
如果我先保存事件,这样可以正常工作,但是我在我工作的上下文中没有这个选项。
以下是我的模特:
class Event < ActiveRecord::Base
#belongs_to :user
has_many :event_locations
has_many :locations, :through => :event_locations
accepts_nested_attributes_for :locations
end
class EventLocation < ActiveRecord::Base
belongs_to :event
belongs_to :location
validates_presence_of :event
validates_presence_of :location
accepts_nested_attributes_for :location
end
class Location < ActiveRecord::Base
has_many :event_locations
has_many :events, :through => :event_locations
end
现在我发现连接模型EventLocation上的验证会导致此问题。
我应该不验证这个吗?有没有不同的方式呢?
答案 0 :(得分:1)
<强> TL; DR 强>
尝试a)
class EventLocation < ActiveRecord::Base
belongs_to :event
belongs_to :location
validates_presence_of :event_id
validates_presence_of :location_id
accepts_nested_attributes_for :location
end
或 - 如果您不需要EventLocation
- b)
class Event < ActiveRecord::Base
#belongs_to :user
has_and_belongs_to_many :locations
accepts_nested_attributes_for :locations
end
class Location < ActiveRecord::Base
has_and_belongs_to_many :events
end
发生了什么事?
在“碰撞”模型EventLocation
中,您验证了:location
和:event
的存在,这会导致您的问题。
要理解为什么会发生这种情况以及如何解决这个问题,我们首先需要了解验证系统的工作原理以及将模型添加到:through
- 集合的内容。
<强>验证强>
在这个特殊情况下,我们validate_presence_of
会告诉模型看一下这个东西,看看它是否存在。
简化为:
validates_presence_of :something
保存时导致
model.save if model.something.present?
所以这个应该检查正确的事情。
:through
- 集合
由于以上显然不能按预期的方式工作,我们可以推断出
event.locations << loc
实际上没有设置
EventLocation.new(location: loc)
所以真正可能发生的是,rails'只是'设置ID
EventLocation.new(location_id: loc.id)
这是什么意思?
假设上述内容是正确的,那么验证id的存在而不是关联的对象可能会解决这个问题。
为什么要这么麻烦?
当然,验证通常不是一个坏主意,但这里可能有另一种选择,那就是has_and_belongs_to_many
。这些方法包含了大量的魔力,使模型能够处理不需要附加模型的碰撞表。
一般来说,如果你不真的需要将任何业务逻辑或附加数据附加到两个表的碰撞中,依靠魔法内置(habtm)做正确的事情为你而不是手动做(并验证)它。