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

103

Как вы редактируете атрибуты модели соединения при использовании accept_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

... и сделайте вложенную форму в themes / 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. Как я могу поместить поля для этих других атрибутов компоновщика в форму «новая тема», чтобы они не были нулевыми?

Арколай
источник
3
Я пытаюсь сделать то же самое, что и вы, только в действии new / create ... Мне интересно, можете ли вы поделиться своими действиями контроллера. Я хочу создать Userсквозной, Accountиспользуя Relationshipв качестве linker... но я не могу понять, как должны выглядеть действия new и create ... не возражаете?
Mohamad

Ответы:

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...
Арколай
источник
13
Дай мне знать, было ли это полезно
Арколай
13
Обновление Rails 3: form_for и field_for требуют <% =%> вместо <
%%
Я бы добавил обратные кавычки кода вокруг двух добавленных вами строк accept_nested_attributes_for. Я неоднократно пропускал эту информацию, просто просматривая код - как только я внимательно ее прочитал, я уловил эту пропущенную деталь, и это решило мою проблему. Спасибо!
TJ Schuck
2
честно говоря, это тот полный пример, который нужен руководствам rubyonrails.org.
ahnbizcad
Визуальная ясность действительно имеет большое значение, Т.Дж. Шак.
ahnbizcad
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
Даниэль Доэзема
источник
Я не уверен, но я думаю , что предполагалось , все вместе сaccepts_nested_attributes_for
Arcolye
2
@Arcolye - Найти эту информацию в Интернете для подобной ассоциации в то время было такой болью - возможно, в тот день у меня не было гугл-фу. Я хотел по крайней мере задокументировать это здесь, поскольку я как мой коллега, и я просто предположил, что рельсы преобразовали связанные_атрибуты в массив, а не в нулевой индексированный хеш. Надеюсь, этот лакомый кусок поможет кому-то в будущем :)
Дэниел Доэзема
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 ассоциации для более подробной информации.

8bithero
источник