Rails вложенная форма с has_many: через, как редактировать атрибуты модели соединения?

Как вы изменяете атрибуты модели соединения при использовании accepts_nested_attributes_for?

У меня есть 3 модели: Темы и Статьи, связанные с 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

Итак, когда я создаю статью в "новом" действии контроллера тем...

@topic.articles.build

... и создайте вложенную форму в topic/new.html.erb...

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

... Rails автоматически создает компоновщик, что отлично. Теперь для моего вопроса: У моей модели Linker также есть атрибуты, которые я хочу изменить в форме "новой темы". Но компоновщик, который автоматически создает Rails, имеет значения nil для всех его атрибутов, кроме topic_id и article_id. Как я могу поместить поля для этих других атрибутов компоновщика в форму "новая тема", чтобы они не выходили из низа?

Ответ 1

Выяснил ответ. Трюк был:

@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...

Ответ 2

Когда форма, сгенерированная 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

Ответ 3

Быстрый GOTCHA для использования has_one в вашем решении. Я просто скопирую вставить ответ, указанный пользователем KandadaBoggu в этот поток.


Подпись 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 ассоциацию документация.