105

How do you edit the attributes of a join model when using accepts_nested_attributes_for?

I have 3 models: Topics and Articles joined by Linkers

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

So when I build the article in the "new" action of the topics controller...

@topic.articles.build

...and make the nested form in topics/new.html.erb...

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

...Rails automatically creates the linker, which is great. Now for my question: My Linker model also has attributes that I want to be able to change via the "new topic" form. But the linker that Rails automatically creates has nil values for all its attributes except topic_id and article_id. How can I put fields for those other linker attributes into the "new topic" form so they don't come out nil?

4

3 回答 3

93

想出了答案。诀窍是:

@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...
于 2010-02-17T07:16:11.607 回答
6

当 Rails 生成的表单提交到 Railscontroller#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
于 2013-05-08T17:31:53.153 回答
3

在您的解决方案中使用 has_one 时的快速GOTCHA。我将在此线程中复制粘贴用户KandadaBoggu给出的答案。


和关联的build方法签名是不同的 。has_onehas_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关联文档以获取更多详细信息。

于 2012-07-18T15:16:32.617 回答