Ruby-on-rails accepts_nested_attributes_for 子关联验证失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/935650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:18:17  来源:igfitidea点击:

accepts_nested_attributes_for child association validation failing

ruby-on-railsvalidationactiverecordnested

提问by Ryan Townsend

I'm using accepts_nested_attributes_for in one of my Rails models, and I want to save the children after creating the parent.

我在我的一个 Rails 模型中使用了 accepts_nested_attributes_for,我想在创建父级后保存子级。

The form works perfectly, but the validation is failing. For simplicity's sake imagine the following:

表单完美运行,但验证失败。为简单起见,请想象以下情况:

class Project < ActiveRecord::Base
  has_many :tasks
  accepts_nested_attributes_for :tasks
end

class Task < ActiveRecord::Base
  belongs_to :project

  validates_presence_of :project_id
  validates_associated :project
end

And I am running:

我正在运行:

Project.create!(
  :name => 'Something',
  :task_attributes => [ { :name => '123' }, { :name => '456' } ]
)

Upon saving the project model, the validation is failing on the tasks because they don't have a project_id (since the project hasn't been saved).

保存项目模型后,任务验证失败,因为它们没有 project_id(因为项目尚未保存)。

It seems like Rails is following the pattern below:

Rails 似乎遵循以下模式:

  • Validate Project
  • Validate Tasks
  • Save Project
  • Save Tasks
  • 验证项目
  • 验证任务
  • 保存项目
  • 保存任务

The pattern should be:

模式应该是:

  • Validate Project
  • On Pass: Save Project and continue...
  • Validate Tasks
    • On Pass: Save Tasks
    • On Fail: Delete Project (rollback maybe?)
  • 验证项目
  • 通过:保存项目并继续...
  • 验证任务
    • 通过时:保存任务
    • 失败时:删除项目(可能回滚?)

So my question boils down to: How can I get Rails to run the project_id= (or project=) method and validation on the children (tasks) AFTER the parent (project) has been saved, but NOT save the parent (project) model if any child (task) is invalid?

所以我的问题归结为:如何让 Rails 在保存父(项目)后运行 project_id=(或 project=)方法和验证子(任务),但不保存父(项目)模型如果任何子项(任务)无效?

Any ideas?

有任何想法吗?

采纳答案by The Who

Use this answer for Rails 2, otherwise see below for the :inverse_ofanswer

将此答案用于 Rails 2,否则请参阅下面的:inverse_of答案

You can work around this by notchecking for the project_id if the associated project is valid.

如果关联的项目有效,您可以通过检查 project_id来解决此问题。


class Task < ActiveRecord::Base
  belongs_to :project

  validates_presence_of :project_id, :unless => lambda {|task| task.project.try(:valid?)}
  validates_associated :project
end

回答by boblin

Use :inverse_ofand validates_presence_of :parent. This should fix your validation problem.

使用:inverse_ofvalidates_presence_of :parent。这应该可以解决您的验证问题。

   class Dungeon < ActiveRecord::Base
     has_many :traps, :inverse_of => :dungeon
   end

   class Trap < ActiveRecord::Base
     belongs_to :dungeon, :inverse_of => :traps
     validates_presence_of :dungeon
   end

http://apidock.com/rails/ActiveModel/Validations/HelperMethods/validates_presence_of

http://apidock.com/rails/ActiveModel/Validations/HelperMethods/validates_presence_of

https://github.com/rails/rails/blob/73f2d37505025a446bb5314a090f412d0fceb8ca/activerecord/test/cases/nested_attributes_test.rb

https://github.com/rails/rails/blob/73f2d37505025a446bb5314a090f412d0fceb8ca/activerecord/test/cases/nested_attributes_test.rb

回答by Fran?ois Beausoleil

Only validate the relationship, not the ID:

仅验证关系,而不验证 ID:

class Task < ActiveRecord::Base
  belongs_to :project

  validates_presence_of :project
end

As soon as the association is populated, ActiveRecord will consider the validation to have succeeded, whether or not the model is saved. You might want to investigate autosaving as well, to ensure the task's project is always saved:

一旦关联被填充,无论模型是否被保存,ActiveRecord 都会认为验证已经成功。您可能还想研究自动保存,以确保始终保存任务的项目:

class Task < ActiveRecord::Base
  belongs_to :project, :autosave => true

  validates_presence_of :project
end

回答by Michael Reinsch

Unfortunately none of the above suggestions work for me with Rails 2.3.5.

不幸的是,上述建议都不适用于 Rails 2.3.5。

In my case, the project in a task is always nil if both are created using nested attributes. Only if I remove the validates_presence_of, the create goes through successfully. The unit test and the log show that all is created correctly.

在我的情况下,如果任务中的项目都是使用嵌套属性创建的,则它们始终为零。只有我删除了validates_presence_of,创建才能成功通过。单元测试和日志显示所有内容均已正确创建。

So I'd now tend to add constraints to the DB instead of Rails as that seems to be more reliable in the first place.

所以我现在倾向于向数据库添加约束而不是 Rails,因为这首先看起来更可靠。

回答by Michael Reinsch

You could just create the project and only add the projects if it passes validation:

您可以创建项目并仅在通过验证时添加项目:

tasks = params.delete(:task_attributes)
if Project.create(params)
  Project.update_attributes(:task_attributes => tasks)
end

Ciao

再见

回答by Thomas Watson

Contrary to what bigo suggests, it's not always acceptable to save the parent object first and then the children. Usually you want to make sure all objects validate before you start saving them. That gives the user the chance to re-edit the input form and correct any errors.

与 bigo 建议的相反,先保存父对象然后再保存子对象并不总是可以接受的。通常,您要确保所有对象在开始保存之前都经过验证。这使用户有机会重新编辑输入表单并更正任何错误。

The problem you describe will be fixed in Rails 3.0. I would have posted a link to the Lighthouse ticket, but stackoverflow.com does not allow this because I'm a new user (#fail). But for the time being, you can use the plugin "parental_control", which will fix your "bug".

您描述的问题将在 Rails 3.0 中修复。我会发布一个指向 Lighthouse 票证的链接,但 stackoverflow.com 不允许这样做,因为我是一个新用户 (#fail)。但是暂时,您可以使用插件“ parental_control”,它将修复您的“错误”。