0

我正在尝试创建一个嵌套的子孙记录。孩子属于父母和孙子女。孩子不会 validates_presence_of 孙子,因为它还没有被保存。

我正在使用 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。

是否有一种简单而优雅的方法来确保在子记录之前构建孙记录(任务)?

我在会议模型中尝试过这样的事情:

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 "Couldn't find Task with ID=XX for Meeting with ID="的奇怪行为 - 我有点明白,但似乎是一条红鲱鱼。

我还尝试将:inverse_of 添加到所有关系并验证:task 而不是:task_id。奇怪的是,后者失败了,但似乎没有给出错误信息。

我在这里的实际目标是创建多个任务,每个任务都有一个关于先前选择的项目的初始会议......所以我可以对我的问题采取另一种方法 - 我可以在控制器中做一些简单而丑陋的事情,或者创建第一个在项目的 after_create 会议上。但这太漂亮了,太接近工作了。我在 :task_field 和 :meeting_field 上得到正确的验证错误这一事实表明我走在正确的轨道上。

我知道问题出在哪里,但不知道如何解决:我怀疑我遗漏了一些明显的东西。

谢谢!

4

1 回答 1

1

好吧,我找到了一个解决方案,基于一个类似的问题,但它的短处是“rails 2.3 似乎不太擅长这个”。我想我可以用比我见过的任何其他答案更简洁的方式来回答这个问题。

您所做的是跳过 :task_id 的验证,但前提是任务有效!我见过的大多数其他答案都使用 proc,但我认为使用委托更具可读性,如下所示:

delegate :valid?, :to => :task, :prefix => true, :allow_nil => true
validates_presence_of :task_id, :unless => :task_valid?

我还有另一个隐藏在水线下的问题 - 在这种情况下,“项目”实际上是我想要保护的一种特殊记录,它的验证(故意)仅针对这个特殊记录失败,我还设置了只读?为真为特殊记录。

即使我实际上并没有更改该特殊记录,它仍然需要验证并且不能只读以通过它更新子级。出于某种原因,我没有看到该验证的错误消息。为了解决这个问题,我对项目进行了验证:on => :create,然后我取出了只读?事物。

但一般的解决方案是“如果对象本身有效,则不验证未构建的 belongs_to 对象的存在”。Nil 永远不会有效,因此如果您只有一个 object_id,验证仍然有效。

(除非您有答案或链接,否则请不要对真诚的问题投反对票。我知道其他人已经以其他方式提出了该问题,我阅读了许多其他问题,似乎都不是同样的问题,我还没有找到解决方案。)

于 2012-05-17T20:39:02.333 回答