Modulo annidato di Rails con has_many: through, come modificare gli attributi del modello di join?


103

Come si modificano gli attributi di un modello di join quando si utilizza accept_nested_attributes_for?

Ho 3 modelli: Argomenti e Articoli uniti da 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

Quindi, quando creo l'articolo nell'azione "nuova" del controller degli argomenti ...

@topic.articles.build

... e crea il modulo annidato in topics / new.html.erb ...

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

... Rails crea automaticamente il linker, il che è fantastico. Ora per la mia domanda: il mio modello Linker ha anche attributi che desidero poter modificare tramite il modulo "nuovo argomento". Ma il linker che Rails crea automaticamente ha valori nulli per tutti i suoi attributi eccetto topic_id e article_id. Come posso inserire i campi per quegli altri attributi del linker nel modulo "nuovo argomento" in modo che non risultino nulli?


3
Sto cercando di fare la stessa cosa che sei tu, solo in una nuova azione / crea ... Mi chiedo se potresti condividere le azioni del tuo controller. Voglio creare Userun Accountutilizzando un Relationshipcome a linker... ma non riesco a capire come dovrebbero essere le azioni new e create ... ti dispiacerebbe?
Mohamad

Risposte:


90

Ho capito la risposta. Il trucco era:

@topic.linkers.build.build_article

Ciò crea i linker, quindi crea l'articolo per ogni linker. Quindi, nei modelli:
topic.rb necessita di accepts_nested_attributes_for :linkers
linker.rbaccepts_nested_attributes_for :article

Quindi nella forma:

<%= 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
Fammi sapere se è stato utile
Arcolye

13
Aggiornamento di Rails 3: form_for e field_for richiedono <% =%> invece di <
%%

Aggiungerei backtick di codice attorno alle due linee accept_nested_attributes_for che hai aggiunto. Mi mancavano ripetutamente quelle informazioni durante la scansione del codice: una volta letto a fondo, ho colto quel dettaglio mancato e ha risolto il mio problema. Grazie!
TJ Schuck

2
onestamente, questo è il tipo di esempio completo di cui hanno bisogno le guide di rubyonrails.org.
ahnbizcad

La chiarezza visiva fa davvero molto, TJ Schuck.
ahnbizcad

6

Quando il form generato da Rails viene inviato a Rails controller#action, paramsavrà una struttura simile a questa (aggiunti alcuni attributi inventati):

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

Si noti come linkers_attributesè effettivamente un indice zero Hashcon le Stringchiavi e non un Array? Bene, questo perché le chiavi del campo del modulo che vengono inviate al server hanno questo aspetto:

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

La creazione del record ora è semplice come:

TopicController < ApplicationController
  def create
    @topic = Topic.create!(params[:topic])
  end
end

Non ne sono sicuro, ma penso che sia stato sempre consideratoaccepts_nested_attributes_for
Arcolye

2
@Arcolye - Trovare queste informazioni su Internet per un'associazione come questa è stato un vero dolore all'epoca - forse il mio google-fu quel giorno era spento. Volevo almeno documentarlo qui poiché io come mio collega e ho semplicemente assunto che rails convertisse linked_attributes in un array, invece di un hash indicizzato zero. Si spera che questo bocconcino aiuti qualcuno in futuro :)
Daniel Doezema

3

Un GOTCHA veloce per quando usi has_one nella tua soluzione. Mi limiterò a copiare e incollare la risposta fornita dall'utente KandadaBoggu in questo thread .


La buildfirma del metodo è diversa per has_onee le has_manyassociazioni.

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

La sintassi di build per l' has_manyassociazione:

user.messages.build

La sintassi di build per l' has_oneassociazione:

user.build_profile  # this will work

user.profile.build  # this will throw error

Leggi la documentazionehas_one dell'associazione per maggiori dettagli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.