Rails ซ้อนรูปแบบ has_many: ถึงวิธีแก้ไขแอตทริบิวต์ของ join model?


103

คุณจะแก้ไขแอตทริบิวต์ของโมเดลการเข้าร่วมได้อย่างไรเมื่อใช้ accept_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

... และสร้างแบบฟอร์มซ้อนในหัวข้อ / new.html.erb ...

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

... Rails สร้างตัวเชื่อมโดยอัตโนมัติซึ่งดีมาก ตอนนี้สำหรับคำถามของฉัน:โมเดล Linker ของฉันยังมีแอตทริบิวต์ที่ฉันต้องการให้เปลี่ยนแปลงผ่านแบบฟอร์ม "หัวข้อใหม่" แต่ตัวเชื่อมโยงที่ Rails สร้างขึ้นโดยอัตโนมัติมีค่าศูนย์สำหรับแอตทริบิวต์ทั้งหมดยกเว้น topic_id และ article_id ฉันจะใส่ฟิลด์สำหรับแอตทริบิวต์ตัวเชื่อมโยงอื่น ๆ ลงในแบบฟอร์ม "หัวข้อใหม่" ได้อย่างไร


3
ฉันกำลังพยายามทำสิ่งเดียวกันกับคุณเฉพาะในการกระทำใหม่ / สร้าง ... ฉันสงสัยว่าคุณสามารถแบ่งปันการทำงานของคอนโทรลเลอร์ได้หรือไม่ ฉันต้องการสร้างUserผ่านการAccountใช้ a Relationshipเป็นlinker... แต่ฉันคิดไม่ออกว่าการกระทำใหม่และการสร้างนั้นมีลักษณะอย่างไร ... คุณจะรังเกียจไหม
Mohamad

คำตอบ:


90

คิดหาคำตอบ เคล็ดลับคือ:

@topic.linkers.build.build_article

ที่สร้างตัวเชื่อมโยงจากนั้นสร้างบทความสำหรับตัวเชื่อมโยงแต่ละคน ดังนั้นในโมเดล:
topic.rb ต้องการความต้องการaccepts_nested_attributes_for :linkers
linker.rbaccepts_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
แจ้งให้เราทราบหากสิ่งนี้มีประโยชน์
Arcolye

13
อัปเดต Rails 3: form_for และ field_for need <% =%> แทน <%%> หากคุณใช้ Rails 3
Arcolye

ฉันจะเพิ่มโค้ด backticks รอบ ๆ สองบรรทัด accept_nested_attributes_for ที่คุณเพิ่ม ฉันพลาดข้อมูลนั้นซ้ำแล้วซ้ำเล่าในขณะที่สแกนโค้ด - เมื่อฉันอ่านอย่างละเอียดแล้วฉันก็พบว่ารายละเอียดที่พลาดไปนั้นช่วยแก้ปัญหาของฉันได้ ขอบคุณ!
TJ Schuck

2
โดยสุจริตนี่คือตัวอย่างเต็มรูปแบบที่ผู้แนะนำ rubyonrails.org ต้องการ
ahnbizcad

ความชัดเจนของภาพนั้นไปได้ไกล TJ Schuck
ahnbizcad

6

เมื่อรูปแบบที่สร้างขึ้นโดยทางรถไฟถูกส่งไปยังราง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 - การค้นหาข้อมูลนี้บนอินเทอร์เน็ตสำหรับการเชื่อมโยงเช่นนี้เป็นความเจ็บปวดในเวลานั้น - บางที Google-fu ของฉันก็หยุดทำงานในวันนั้น อย่างน้อยฉันต้องการบันทึกไว้ที่นี่ในขณะที่ฉันเป็นเพื่อนร่วมงานของฉันและฉันแค่คิดว่ารางแปลง linked_attributes เป็นอาร์เรย์แทนที่จะเป็นแฮชที่จัดทำดัชนีเป็นศูนย์ หวังว่าเรื่องนี้จะช่วยใครบางคนในอนาคต :)
Daniel Doezema

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เชื่อมโยงสำหรับรายละเอียดเพิ่มเติม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.