使用accepts_nested_attributes_for时如何编辑连接模型的属性?
我有3个模型:由连接器加入的主题和文章
class Topic < ActiveRecord::Base
has_many :linkers
has_many :articles, :through => :linkers, :foreign_key => :article_id
accepts_nested_attributes_for :articles
end
class Article < ActiveRecord::Base
has_many :linkers
has_many :topics, :through => :linkers, :foreign_key => :topic_id
end
class Linker < ActiveRecord::Base
#this is the join model, has extra attributes like "relevance"
belongs_to :topic
belongs_to :article
end
所以当我在主题控制器的“新”动作中构建文章时......
@topic.articles.build
...并在topics / new.html.erb中创建嵌套表单...
<% form_for(@topic) do |topic_form| %>
...fields...
<% topic_form.fields_for :articles do |article_form| %>
...fields...
... Rails会自动创建链接器,这很棒。 现在我的问题是: 我的链接器模型还有我希望能够通过“新主题”表单更改的属性。但是Rails自动创建的链接器除了topic_id和article_id之外,其所有属性都有nil值。如何将其他链接器属性的字段放入“新主题”表单中,这样它们就不会出现?
答案 0 :(得分:90)
找出答案。诀窍是:
@topic.linkers.build.build_article
构建链接器,然后为每个链接器构建文章。所以,在模型中:
topic.rb需要accepts_nested_attributes_for :linkers
linker.rb需要accepts_nested_attributes_for :article
然后是以下形式:
<%= form_for(@topic) do |topic_form| %>
...fields...
<%= topic_form.fields_for :linkers do |linker_form| %>
...linker fields...
<%= linker_form.fields_for :article do |article_form| %>
...article fields...
答案 1 :(得分:6)
当Rails生成的表单提交给Rails controller#action
时,params
将具有与此类似的结构(添加了一些组成的属性):
params = {
"topic" => {
"name" => "Ruby on Rails' Nested Attributes",
"linkers_attributes" => {
"0" => {
"is_active" => false,
"article_attributes" => {
"title" => "Deeply Nested Attributes",
"description" => "How Ruby on Rails implements nested attributes."
}
}
}
}
}
请注意linkers_attributes
实际上是如何使用Hash
密钥进行零索引String
,而不是Array
?好吧,这是因为发送到服务器的表单字段键如下所示:
topic[name]
topic[linkers_attributes][0][is_active]
topic[linkers_attributes][0][article_attributes][title]
创建记录现在很简单:
TopicController < ApplicationController
def create
@topic = Topic.create!(params[:topic])
end
end
答案 2 :(得分:3)
在解决方案中使用has_one时的快速GOTCHA。 我将只复制用户KandadaBoggu在this thread中给出的答案。
build
方法签名与has_one
和has_many
关联不同。
class User < ActiveRecord::Base
has_one :profile
has_many :messages
end
has_many
关联的构建语法:
user.messages.build
has_one
关联的构建语法:
user.build_profile # this will work
user.profile.build # this will throw error
阅读has_one
协会documentation了解详情。