accepts_nested_attributes_for子关联验证失败

Rya*_*end 71 validation activerecord nested ruby-on-rails

我在我的一个Rails模型中使用accepts_nested_attributes_for,我想在创建父节点后保存子节点.

表单完美无缺,但验证失败.为简单起见,请想象以下内容:

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
Run Code Online (Sandbox Code Playgroud)

而我正在运行:

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

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

似乎Rails遵循以下模式:

  • 验证项目
  • 验证任务
  • 保存项目
  • 保存任务

模式应该是:

  • 验证项目
  • 通过:保存项目并继续......
  • 验证任务
    • 通过:保存任务
    • 失败:删除项目(可能会回滚?)

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

有任何想法吗?

bob*_*lin 161

使用: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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这应该是公认的答案,因为另一个只是一种解决方法. (11认同)
  • 在Rails 3.0上为我工作 (3认同)

The*_*Who 12

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

如果关联项目有效,则可以通过检查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
Run Code Online (Sandbox Code Playgroud)

  • 对于Rails 3.0及更高版本,下面的inverse_of解决方案更正确. (10认同)

Fra*_*eil 9

仅验证关系,而不是ID:

class Task < ActiveRecord::Base
  belongs_to :project

  validates_presence_of :project
end
Run Code Online (Sandbox Code Playgroud)

一旦填充了关联,ActiveRecord就会认为验证成功,无论模型是否已保存.您可能还想调查自动保存,以确保始终保存任务的项目:

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

  validates_presence_of :project
end
Run Code Online (Sandbox Code Playgroud)