带有 has_many: through 的 Rails 嵌套表单,如何编辑连接模型的属性?

如何编辑联接模型的属性时,使用接受 _ 嵌套 _ 属性 _ 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

因此,当我在主题控制器的“ new”操作中构建文章时..。

@topic.articles.build

... 并在主题/new.html. erb 中嵌套表单..。

<% form_for(@topic) do |topic_form| %>
...fields...
<% topic_form.fields_for :articles do |article_form| %>
...fields...

... Rails 会自动创建链接器,这很棒。 现在回答我的问题: 我的 Linker 模型也有一些属性,我希望能够通过“新主题”表单进行更改。但是 Rails 自动创建的链接器的所有属性都是 nil 值,除了 subject _ id 和 article _ id。如何将其他链接器属性的字段放入“新主题”表单中,这样它们就不会显示为空?

40812 次浏览

Figured out the answer. The trick was:

@topic.linkers.build.build_article

That builds the linkers, then builds the article for each linker. So, in the models:
topic.rb needs accepts_nested_attributes_for :linkers
linker.rb needs accepts_nested_attributes_for :article

Then in the form:

<%= 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...

A quick GOTCHA for when using has_one in your solution. I will just copy paste the answer given by user KandadaBoggu in this thread.


The build method signature is different for has_one and has_many associations.

class User < ActiveRecord::Base
has_one :profile
has_many :messages
end

The build syntax for has_many association:

user.messages.build

The build syntax for has_one association:

user.build_profile  # this will work


user.profile.build  # this will throw error

Read the has_one association documentation for more details.

When the form generated by Rails is submitted to the Rails controller#action, the params will have a structure similar to this (some made up attributes added):

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."
}
}
}
}
}

Notice how linkers_attributes is actually a zero-indexed Hash with String keys, and not an Array? Well, this is because the form field keys that are sent to the server look like this:

topic[name]
topic[linkers_attributes][0][is_active]
topic[linkers_attributes][0][article_attributes][title]

Creating the record is now as simple as:

TopicController < ApplicationController
def create
@topic = Topic.create!(params[:topic])
end
end