103 votes

Formulaire Rails imbriqué avec has_many :through, comment modifier les attributs du modèle de jointure ?

Comment modifier les attributs d'un modèle de jointure lorsque l'on utilise accepts_nested_attributes_for ?

Je possède 3 modèles : Sujets et articles rejoints par les 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

Ainsi, lorsque je crée l'article dans l'action "new" du contrôleur des sujets...

@topic.articles.build

...et faire le formulaire imbriqué dans topics/new.html.erb...

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

...Rails crée automatiquement le linker, ce qui est génial. Maintenant, ma question : Mon modèle Linker possède également des attributs que je veux pouvoir modifier via le formulaire "new topic". Mais le linker que Rails crée automatiquement a des valeurs nulles pour tous ses attributs, sauf topic_id et article_id. Comment puis-je placer les champs pour les autres attributs du linker dans le formulaire "new topic" afin qu'ils ne soient pas nuls ?

90voto

Arcolye Points 2602

14 jours plus tard - J'ai trouvé la réponse. J'espère que ma prochaine question recevra une réponse. Le truc était :

@topic.linkers.build.build_article

Cela construit les linkers, puis construit l'article pour chaque linker. Donc, dans les modèles :
topic.rb a besoin accepts_nested_attributes_for :linkers
linker.rb a besoin de accepts_nested_attributes_for :article

Puis dans le formulaire :

<%= 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...

6voto

Daniel Doezema Points 1328

J'ai honnêtement essayé d'en faire une Edit sur la réponse acceptée mais elle a été rejetée alors je vais juste en faire une autre "réponse".

Lorsque le formulaire généré par rails est soumis à rails controller#action le site params aura une structure similaire à celle-ci (quelques attributs inventés ajoutés) :

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

Remarquez comment linkers_attributes est en fait une indexation zéro. Hash avec String et non un Array ? Eh bien, c'est parce que les clés des champs du formulaire qui sont envoyées au serveur ressemblent à ceci :

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

La création de l'enregistrement est désormais aussi simple que cela :

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

3voto

8bithero Points 581

Un petit GOTCHA pour l'utilisation de has_one dans votre solution. Je vais simplement copier-coller la réponse donnée par l'utilisateur KandadaBoggu sur ce fil .


Le site build La signature de la méthode est différente pour has_one et has_many associations.

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

La syntaxe de construction pour has_many association :

user.messages.build

La syntaxe de construction pour has_one association :

user.build_profile  # this will work

user.profile.build  # this will throw error

Lire l'article has_one association documentation pour plus de détails.

2voto

Rich Peck Points 26701

Merci beaucoup les gars - j'ai travaillé pendant des jours pour résoudre ce problème !

Une chose pour toi accepts_nested_attributes_for :article

Vous devez le garder au singulier car il s'agit d'une relation belongs_to.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X