如果其中一个记录未通过验证,则创建具有嵌套关联的记录将无法保存任何关联的记录。
class Podcast < ActiveRecord::Base
has_many :episodes, inverse_of: :podcast
accepts_nested_attributes_for :episodes
end
class Episode < ActiveRecord::Base
belongs_to :podcast, inverse_of: :episodes
validates :podcast, :some_attr, presence: true
end
# Creates a podcast with one episode.
case_1 = Podcast.create {
title: 'title'
episode_attributes: [
{title: "ep1", some_attr: "some_attr"}, # <- Valid Episode
]
}
# Creates a podcast without any episodes.
case_2 = Podcast.create {
title: 'title'
episode_attributes: [
{title: "ep1", some_attr: "some_attr"}, # <- Valid Episode
{title: "ep2"} # <- Invalid Episode
]
}
我希望case_1
能够成功保存一个已创建的剧集。
我希望case_2
做两件事之一:
相反,播客会保存,但这两集都没有。
我希望播客能够保存任何有效的剧集。
我想通过将接受嵌套属性行更改为
来拒绝无效剧集accepts_nested_attributes_for :episodes, reject_if: proc { |attributes| !Episode.new(attributes).valid? }
但每一集都无效,因为他们还没有podcast_id
,所以他们会失败validates :podcast, presence: true
答案 0 :(得分:2)
尝试此模式:在accepts_nested_attributes_for指令(docs)中使用:reject_if param并传递方法以发现属性是否有效。这样您就可以将验证卸载到Episode模型中。
像...一样的东西。
accepts_nested_attributes_for :episodes, :reject_if => :reject_episode_attributes?
def reject_episode_attributes?( attributes )
!Episode.attributes_are_valid?( attributes )
end
然后在剧集中你制作了一个测试你喜欢的方法。您甚至可以创建新记录并使用现有验证。
def self.attributes_are_valid?( attributes )
new_e = Episode.new( attributes )
new_e.valid?
end
答案 1 :(得分:1)
您可以使用validates_associated导致第二个选项(无法保存并显示验证错误)
class Podcast < ActiveRecord::Base
has_many :episodes, inverse_of: :podcast
validates_associated :episodes
accepts_nested_attributes_for :episodes
end
更新:
要做选项一(保存一集)你可以这样做: 1.添加validates_associated:剧集 2.在保存@podcast失败后,在控制器的创建操作中添加代码。首先,检查@ podcast.errors对象,看看故障是否是由剧集的验证错误引起的(只有那个),否则正常处理。如果由剧集上的验证错误引起,那么请执行@ podcast.episodes.each {| e | @ podcast.episodes.delete(e)除非e.errors.empty?}然后再次保存。
这看起来像是:
def create
@podcast = Podcast.new(params[:podcast])
if @podcast.save
redirect_to @podcast
else
if #some conditions looking at @podcast.errors to see that it's failed because of the validates episodes
@podcast.episodes.each do |episode|
@podcast.episodes.delete(episode) unless episode.errors.empty?
end
if @podcast.save
redirect_to @podcast
else
render :new
end
else
render :new
end
end
end
答案 2 :(得分:0)
要获得第一个选项,请尝试为您的剧集启用自动保护功能。
class Podcast < ActiveRecord::Base
has_many :episodes, inverse_of: :podcast, autosave: true
accepts_nested_attributes_for :episodes
end