accepted_nested_attributes_for儿童关联validation失败
我在我的一个Rails模型中使用了accep_nested_attributes_for,我想在创build父项之后保存子项。
表单完美,但validation失败。 为了简单起见,想象如下:
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
而我正在运行:
Project.create!( :name => 'Something', :task_attributes => [ { :name => '123' }, { :name => '456' } ] )
在保存项目模型时,validation在任务上失败,因为他们没有project_id(因为项目没有被保存)。
看来Rails正在遵循以下模式:
- validation项目
- validation任务
- 保存项目
- 保存任务
该模式应该是:
- validation项目
- 通过:保存项目并继续…
- validation任务
- 通过:保存任务
- 在失败:删除项目(回滚也许?)
所以我的问题归结为:如何让Rails运行project_id =(或project =)方法和validation子项(任务)后父(项目)已被保存,但不保存父(项目)模型如果有任何小孩(任务)无效?
有任何想法吗?
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
使用:inverse_of
和validates_presence_of :parent
。 这应该解决您的validation问题。
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
只validation关系,而不是ID:
class Task < ActiveRecord::Base belongs_to :project validates_presence_of :project end
一旦关联被填充,ActiveRecord就会认为validation已经成功,不pipe模型是否被保存。 您也可能要调查自动保存,以确保任务的项目始终保存:
class Task < ActiveRecord::Base belongs_to :project, :autosave => true validates_presence_of :project end
不幸的是,上面的所有build议都不适用于Rails 2.3.5。
在我的情况下,任务中的项目总是为零,如果两者都是使用嵌套属性创build的。 只有当我删除validates_presence_of,创build成功。 unit testing和日志显示所有创build正确。
所以我现在倾向于将约束添加到数据库,而不是Rails,因为这似乎是更可靠的。
您可以创build项目,只有在通过validation时才添加项目:
tasks = params.delete(:task_attributes) if Project.create(params) Project.update_attributes(:task_attributes => tasks) end
再见
与bigobuild议的不同,先保存父对象然后再保存子对象并不总是可以接受的。 通常你想在开始保存之前确认所有的对象都是有效的。 这使用户有机会重新编辑input表单并更正任何错误。
你所描述的问题将在Rails 3.0中得到解决。 我会张贴一个链接到灯塔票,但stackoverflow.com不允许这个,因为我是一个新用户(#fail)。 但暂时,你可以使用插件“ parental_control ”,这将修复你的“错误”。