使用Rails嵌套模型来“创建”外部对象并同时“编辑”现有的嵌套对象?
|
使用Rails 2.3.8
目标是创建一个Blogger,同时更新嵌套的用户模型(以防信息已更改等),或者创建一个全新的用户(如果尚不存在)。
模型:
class Blogger < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end
Blogger控制器:
def new
@blogger = Blogger.new
if user = self.get_user_from_session
@blogger.user = user
else
@blogger.build_user
end
# get_user_from_session returns existing user
# saved in session (if there is one)
end
def create
@blogger = Blogger.new(params[:blogger])
# ...
end
形成:
<% form_for(@blogger) do |blogger_form| %>
<% blogger_form.fields_for :user do |user_form| %>
<%= user_form.label :first_name %>
<%= user_form.text_field :first_name %>
# ... other fields for user
<% end %>
# ... other fields for blogger
<% end %>
当我通过嵌套模型创建新用户时,工作正常,但如果嵌套用户已经存在并且具有ID(在这种情况下,我希望它仅更新该用户),则失败。
错误:
Couldn\'t find User with ID=7 for Blogger with ID=
这个SO问题处理了一个类似的问题,只有答案表明Rails不会那样工作。答案是建议简单地传递现有项目的ID,而不是显示其形式-效果很好,除非我想允许对User属性(如果有)进行编辑。
深度嵌套的Rails表单使用before_to无法正常工作?
有什么建议吗?这似乎不是特别罕见的情况,而且似乎必须有解决方案。
没有找到相关结果
已邀请:
3 个回复
瞧叮
)的
关联(
)在Rails 3.2.8(或Rails 2.3.8中,没关系,尽管我希望您现在已经升级到3.x)...并非没有一些解决方法。 我发现2个变通办法似乎有效(在Rails 3.2.8中)。要了解它们为什么起作用,您应该首先了解引起错误的代码。 了解为什么ActiveRecord引发错误... 在我的activerecord版本(3.2.8)中,可以在
中找到处理为
关联分配嵌套属性的代码,如下所示:
在
语句中,如果看到您传递了用户ID(
),它将尝试从博客的
关联(
,association_name为
)中获取现有的
记录。 但是,由于这是一个新建的
对象,因此blogger.user最初将为
,因此它将无法处理处理现有ѭ19的分支中的
调用。这就是我们需要解决的问题(请参阅下一节)。 因此,它移至第一个“ 20”分支,该分支再次检查是否存在用户标识(“ 21”)。它存在,因此它将检查下一个条件
。 由于您要使用
初始化新的Blogger对象(即,不传递
或
),因此它将使用默认的
。
是正确的,因此继续进行
,这是您看到的错误。 最后,如果其他两个都没有分支,它将检查是否应拒绝新记录,并(如果不是)则继续建立新记录。这是您提到的“如果还不存在,则创建新用户”案例中遵循的路径。 解决方法1(不推荐):
我想到的第一个解决方法-但不建议使用-是使用
将属性分配给Blogger对象(Rails 3.2.8)。
这样,它将跳过第一个
并转到最后一个
,后者将使用参数中的所有属性(包括
)建立一个新用户。实际上,我不知道这是否会导致它像您想要的那样更新现有的用户记录(可能不是,还没有真正测试过该选项),但是至少它避免了错误... :) 解决方法2(建议):在
中设置
但是,我建议的解决方法是,实际上是从:id参数初始化/设置
关联,以便使用第一个
分支,并根据需要更新内存中的现有记录...
为了能够像这样覆盖嵌套的属性访问器并调用ѭ41,您需要使用Edge Rails或包含我在https://github.com/rails/rails/pull发布的猴子补丁/ 2945。另外,您也可以直接从
设定器中拨打
,而不用拨打
。 如果要使其始终创建新的用户记录,而不更新现有的用户... 就我而言,我最终决定我不希望人们能够从此表单中更新现有的用户记录,因此我最终使用了上面的变通方法的一些细微变化:
这种方法还可以防止错误的发生,但是却有所不同。 如果在参数中传递了一个id,而不是使用它来初始化
关联,我只是删除传入的id,这样它就可以从其余提交的用户参数中退回到构建一个
用户。
舞备联
假设参数看起来像... {:report => {:name => \“ name \”,:user_attributes => {:id => 1,{:things_attributes => {\“ 1 \” => {:name => \“事物名称\ “}}}}}}
济畦刨
嵌套的保存将使用它来确定它是用户的创建还是更新。