我正在尝试创建一个嵌套的子孙记录。孩子属于父母和孙子。孩子不会对孙子进行验证_存在_因为它尚未保存。
我正在使用Rails 2.3.11,Formtastic,InheritedResources和Haml,其他一切似乎也能正常工作 - 例如,孙子的验证错误在父表单中正确填充,并且记住无效值并显示给用户。除非一切都有效,否则父模型甚至不会尝试更新。
我的代码是这样的,但是在不同的问题域中:
class Project < ActiveRecord::Base
has_many :meetings, :dependent => :destroy
accepts_nested_attributes_for :meetings
end
class Meeting < ActiveRecord::Base
belongs_to :project
belongs_to :task
accepts_nested_attributes_for :task
validates_presence_of :task_id, :project_id
end
class Task < ActiveRecord::Base
has_many :meetings, :dependent => :destroy
end
项目已经存在,并且可能已经有我们不希望看到的会议。任务可能通过其他会议属于其他项目,但在这种情况下,任务和会议始终是新的。
在控制器中,我仅在新操作
上构建空白记录@project.meetings.build
并保存这样的数据:
@project.update_attributes(params[:project])
并在视图中
- semantic_form_for @project do |f|
- f.semantic_fields_for :meetings do |m|
- next unless m.object.new_record?
= m.semantic_errors :task_id
- m.object.build_task unless i.object.task
- m.semantic_fields_for :task do |t|
- f.inputs do
= t.input :task_field
= m.input :meeting_field
当我尝试保存表单时,出现“任务不能为空”的验证错误。嗯,当然,任务还没有保存,我正在尝试验证,而且我没有它的ID。
是否有一种简单而优雅的方法可以确保在子记录之前构建孙子记录(Task)?
我在会议模型中尝试过类似的内容:
before_validation_on_create do |meeting|
meeting.task.save if meeting.task.valid?
end
这似乎保存了任务,但会议仍然无法获得正确的ID。相同的错误,但创建了任务记录。
我也试过这个:
before_validation_on_create do |meeting|
new_task = meeting.task.save if meeting.task.valid?
meeting.task = new_task
end
提升ActiveRecord :: RecordNotFound有一种奇怪的行为“找不到具有ID = XX的任务会议ID =” - 我有点得到,但看起来像是一个红色的鲱鱼。
我还尝试在所有关系中添加:inverse_of并验证:task而不是:task_id。奇怪的是,后者失败但似乎没有给出任何错误信息。
我在这里的实际目标是创建多个任务,每个任务都有一个以前选择的项目的初始会议...所以我可以采取另一种方法解决我的问题 - 我可以在控制器中做一些简单和丑陋的事情,或者在项目的after_create中创建第一个会议。但这太漂亮了,太靠近工作了。我在以下问题上得到了正确的验证错误:task_field和:meeting_field意味着我在正确的轨道上。
我知道问题是什么,但不知道如何解决问题:我怀疑我错过了一些明显的问题。
谢谢!
答案 0 :(得分:1)
嗯,我找到了一个解决方案,基于其中一个类似的问题,但缺点是&#34; rails 2.3似乎并不擅长这个。&#34;我想我能以比我见过的任何其他答案更简洁的方式提出答案。
您所做的是跳过:task_id的验证,但仅限于任务有效!我见过的大多数其他答案都使用了proc,但我认为使用委托更具可读性,如下所示:
delegate :valid?, :to => :task, :prefix => true, :allow_nil => true
validates_presence_of :task_id, :unless => :task_valid?
我还在水线下隐藏了另一个问题 - 在这种情况下,&#34;项目&#34;实际上是一种我想要保护的特殊记录,它有一个(故意)只为这个特殊记录失败的验证,而且我还设置了readonly?对于特殊记录来说是真的。
即使我实际上并没有更改该特殊记录,它仍然需要验证,并且无法通过它来更新子项。出于某种原因,我没有看到该验证的错误消息。为了解决这个问题,我对项目的验证仅适用:on =&gt; :创造,我拿出了readonly?的事情。
但是一般的解决方案是,如果对象本身有效,则不要验证未构建的belongs_to对象的存在。&#34; Nil永远不会有效,因此如果你只有一个object_id,验证仍然有效。
(除非你有答案或链接到一个问题,否则请不要对一个真诚的问题进行投票。我知道其他人已经通过其他方式询问了这个问题。那些其他问题,似乎没有一个问题,我没有找到解决方案。)