0

我试图弄清楚如何做这样的事情:

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 上的验证会导致这个问题。

我不应该验证吗?有不同的方法吗?

4

1 回答 1

1

TL;博士

尝试任一)

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-collection 的作用。

验证

在这种特殊情况下,我们validate_presence_of有一些东西,它告诉模型查看那个东西,看看它是否存在。

简化:

validates_presence_of :something

保存时,会导致

model.save if model.something.present?

所以这应该是检查正确的事情。

怎么样:through-collections

由于上述显然不能按预期方式工作,我们可以推断

event.locations << loc

实际上并没有设置

EventLocation.new(location: loc)

所以真正可能发生的是,rails“只是”设置ID

EventLocation.new(location_id: loc.id)

这意味着什么?

假设上面是正确的,验证 ids 而不是关联对象的存在可能会在这里解决问题。

何必?

当然,验证通常不是一个坏主意,但这里可能有一个替代方案,那就是has_and_belongs_to_many. 该方法包含很多魔法,它使模型能够处理不需要附加模型的碰撞表。

一般来说,如果你真的不需要为两张表的碰撞附加任何业务逻辑或额外的数据,依靠内置的魔法(habtm)为你做正确的事情,而不是做(和验证)它手动。

于 2013-10-29T22:57:57.460 回答