Rails nested form dengan has_many: through, bagaimana cara mengedit atribut model gabungan?

103

Bagaimana Anda mengedit atribut model gabungan saat menggunakan accepts_nested_attributes_for?

Saya memiliki 3 model: Topik dan Artikel bergabung dengan Linker

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

Jadi, ketika saya membuat artikel di tindakan "baru" dari pengontrol topik ...

@topic.articles.build

... dan buat formulir bersarang di topics / new.html.erb ...

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

... Rails secara otomatis membuat linker, yang sangat bagus. Sekarang untuk pertanyaan saya: Model Linker saya juga memiliki atribut yang ingin saya ubah melalui formulir "topik baru". Tetapi linker yang dibuat secara otomatis oleh Rails memiliki nilai nihil untuk semua atributnya kecuali topic_id dan article_id. Bagaimana cara meletakkan bidang untuk atribut penaut lainnya ke dalam formulir "topik baru" agar tidak nihil?

Arcolye
sumber
3
Saya mencoba melakukan hal yang sama dengan Anda, hanya dalam tindakan baru / buat ... Saya ingin tahu apakah Anda dapat membagikan tindakan pengontrol Anda. Saya ingin membuat Usermelalui Accountmenggunakan a Relationshipsebagai linker... tetapi saya tidak tahu seperti apa tindakan baru dan buat yang dimaksud ... maukah Anda?
Mohamad

Jawaban:

90

Menemukan jawabannya. Triknya adalah:

@topic.linkers.build.build_article

Itu membangun penaut, lalu membuat artikel untuk setiap penaut. Jadi, dalam model:
topic.rb membutuhkan kebutuhan accepts_nested_attributes_for :linkers
linker.rbaccepts_nested_attributes_for :article

Kemudian di bentuk:

<%= 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...
Arcolye
sumber
13
Beri tahu saya jika ini membantu
Arcolye
13
Pembaruan Rails 3: kebutuhan form_for dan field_for <% =%> daripada <%%> jika Anda menggunakan Rails 3.
Arcolye
Saya akan menambahkan kode backticks di sekitar dua baris accepts_nested_attributes_for yang Anda tambahkan. Saya melewatkan info itu berulang kali saat hanya memindai kode - setelah saya membacanya dengan saksama, saya menangkap detail yang terlewat itu dan itu menyelesaikan masalah saya. Terima kasih!
TJ Schuck
2
sejujurnya, ini adalah contoh lengkap yang dibutuhkan oleh pemandu rubyonrails.org.
ahnbizcad
Kejernihan visual sangat berpengaruh, TJ Schuck.
ahnbizcad
6

Ketika formulir yang dihasilkan oleh Rails dikirimkan ke Rails controller#action, paramsakan memiliki struktur yang mirip dengan ini (beberapa atribut dibuat ditambahkan):

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

Perhatikan bagaimana linkers_attributessebenarnya indeks nol Hashdengan Stringkunci, dan bukan Array? Nah, ini karena kunci bidang formulir yang dikirim ke server terlihat seperti ini:

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

Membuat record sekarang sesederhana:

TopicController < ApplicationController
  def create
    @topic = Topic.create!(params[:topic])
  end
end
Daniel Doezema
sumber
Saya tidak yakin, tapi saya pikir itu telah diasumsikan selama iniaccepts_nested_attributes_for
Arcolye
2
@Arcolye - Menemukan informasi ini di internet untuk asosiasi seperti ini sangat menyebalkan pada saat itu - mungkin google-fu saya mati hari itu. Saya ingin setidaknya mendokumentasikannya di sini karena saya sebagai rekan kerja saya dan saya hanya mengasumsikan rel mengubah linked_attributes ke array, alih-alih hash yang diindeks nol. Semoga berita gembira ini membantu seseorang di masa depan :)
Daniel Doezema
3

GOTCHA cepat saat menggunakan has_one dalam solusi Anda. Saya hanya akan menyalin dan menempel jawaban yang diberikan oleh pengguna KandadaBoggu di utas ini .


Tanda buildtangan metode berbeda untuk asosiasi has_onedan has_many.

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

Sintaks build untuk has_manypengaitan:

user.messages.build

Sintaks build untuk has_onepengaitan:

user.build_profile  # this will work

user.profile.build  # this will throw error

Baca dokumentasihas_one asosiasi untuk lebih jelasnya.

8bithero
sumber