Rails的嵌套窗体has_many:通过,如何编辑连接模型的属性?
如何在使用accept_nested_attributes_for时编辑连接模型的属性?
我有3个模型:由连接器join的主题和文章
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
所以,当我在主题控制器的“新”动作中构build文章…
@topic.articles.build
…并在主题/ new.html.erb中嵌套的forms…
<% form_for(@topic) do |topic_form| %> ...fields... <% topic_form.fields_for :articles do |article_form| %> ...fields...
… Rails自动创build链接器,这是伟大的。 现在对于我的问题:我的链接器模型也有属性,我希望能够通过“新主题”forms进行更改。 但是Rails自动创build的链接器对于除了topic_id和article_id之外的所有属性都具有nil值。 我怎样才能把字段的其他链接器属性到“新主题”forms,所以他们不出来零?
找出答案。 诀窍是:
@topic.linkers.build.build_article
构build连接器,然后为每个链接器构build文章。 所以,在模型中:
topic.rb需要accept_nested_attributes_for accepts_nested_attributes_for :linkers
linker.rb需要accept_nested_attributes_for 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...
当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
实际上是一个零索引的使用String
键的Hash
,而不是一个Array
? 那么,这是因为发送到服务器的表单字段键如下所示:
topic[name] topic[linkers_attributes][0][is_active] topic[linkers_attributes][0][article_attributes][title]
创buildlogging现在简单如下:
TopicController < ApplicationController def create @topic = Topic.create!(params[:topic]) end end
在解决scheme中使用has_one时的快速GOTCHA。 我只是复制粘贴用户KandadaBoggu在这个线程给出的答案。
has_one
和has_many
关联的build
方法签名是不同的。
class User < ActiveRecord::Base has_one :profile has_many :messages end
has_many
关联的构build语法:
user.messages.build
has_one
关联的构build语法:
user.build_profile # this will work user.profile.build # this will throw error
阅读has_one
关联文档以获取更多详细信息。