Rails verschachteltes Formular mit has_many: bis, wie werden Attribute des Join-Modells bearbeitet?

103

Wie bearbeiten Sie die Attribute eines Join-Modells, wenn Sie accept_nested_attributes_for verwenden?

Ich habe 3 Modelle: Themen und Artikel, denen Linker beitreten

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

Also, wenn ich den Artikel in der "neuen" Aktion des Themen-Controllers baue ...

@topic.articles.build

... und erstellen Sie das verschachtelte Formular in den Themen / new.html.erb ...

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

... Rails erstellt automatisch den Linker, was großartig ist. Nun zu meiner Frage: Mein Linker-Modell hat auch Attribute, die ich über das Formular "Neues Thema" ändern möchte. Der von Rails automatisch erstellte Linker hat jedoch für alle Attribute außer topic_id und article_id keine Werte. Wie kann ich Felder für diese anderen Linkerattribute in das Formular "Neues Thema" einfügen, damit sie nicht gleich Null werden?

Arcolye
quelle
3
Ich versuche, dasselbe zu tun, was Sie sind, nur in einer neuen / erstellten Aktion ... Ich frage mich, ob Sie Ihre Controller-Aktionen teilen könnten. Ich möchte ein Userdurch ein AccountVerwenden eines Relationshipals linker... erstellen, aber ich kann nicht herausfinden, wie die neuen und erstellten Aktionen aussehen sollen ... würde es Ihnen etwas ausmachen?
Mohamad

Antworten:

90

Ich habe die Antwort herausgefunden. Der Trick war:

@topic.linkers.build.build_article

Dadurch werden die Linker und dann der Artikel für jeden Linker erstellt. Also, in den Modellen:
topic.rb braucht accepts_nested_attributes_for :linkers
linker.rb brauchtaccepts_nested_attributes_for :article

Dann in der Form:

<%= 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
quelle
13
Lassen Sie mich wissen, ob dies hilfreich war
Arcolye
13
Rails 3-Update: form_for und field_for benötigen <% =%> anstelle von <
%%
Ich würde Code-Backticks um die beiden Zeilen "accept_nested_attributes_for" hinzufügen, die Sie hinzugefügt haben. Ich habe diese Informationen wiederholt übersehen, während ich nur den Code gescannt habe. Nachdem ich sie gründlich gelesen hatte, habe ich dieses fehlende Detail erkannt und mein Problem gelöst. Vielen Dank!
TJ Schuck
2
Ehrlich gesagt ist dies die Art von vollständigem Beispiel, die die rubyonrails.org-Anleitungen benötigen.
Ahnbizcad
Visuelle Klarheit ist wirklich ein langer Weg, TJ Schuck.
Ahnbizcad
6

Wenn das von Rails generierte Formular an Rails gesendet wird controller#action, hat das paramseine ähnliche Struktur (einige zusammengesetzte Attribute wurden hinzugefügt):

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

Beachten Sie, wie linkers_attributesist eigentlich eine Null Hashmit StringIndizes indiziert und nicht eine Array? Dies liegt daran, dass die an den Server gesendeten Formularfeldschlüssel folgendermaßen aussehen:

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

Das Erstellen des Datensatzes ist jetzt so einfach wie:

TopicController < ApplicationController
  def create
    @topic = Topic.create!(params[:topic])
  end
end
Daniel Doezema
quelle
Ich bin nicht sicher, aber ich denke, das wurde die ganze Zeit zusammen mitaccepts_nested_attributes_for
Arcolye
2
@Arcolye - Das Finden dieser Informationen im Internet für einen Verein wie diesen war zu dieser Zeit so schmerzhaft - vielleicht war mein Google-Fu an diesem Tag nicht in Betrieb. Ich wollte es hier zumindest dokumentieren, da ich als mein Mitarbeiter und ich nur angenommen haben, dass Rails linked_attributes in ein Array konvertiert hat, anstatt in einen mit Null indizierten Hash. Hoffentlich hilft dieser Leckerbissen jemandem in der Zukunft :)
Daniel Doezema
3

Ein schnelles GOTCHA für die Verwendung von has_one in Ihrer Lösung. Ich werde einfach die Antwort des Benutzers KandadaBoggu in diesen Thread kopieren und einfügen .


Die buildMethodensignatur unterscheidet sich für has_oneund has_manyAssoziationen.

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

Die Build-Syntax für die has_manyZuordnung:

user.messages.build

Die Build-Syntax für die has_oneZuordnung:

user.build_profile  # this will work

user.profile.build  # this will throw error

Lesen Sie den has_oneVerein Dokumentation für weitere Details.

8bithero
quelle