web-dev-qa-db-fra.com

Rails forme imbriquée avec has_many: à travers, comment modifier les attributs du modèle de jointure?

Comment modifier les attributs d'un modèle de jointure lors de l'utilisation de accept_nested_attributes_for?

J'ai 3 modèles: Sujets et articles joints par 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

Alors quand je construis l'article dans la "nouvelle" action du contrôleur de sujets ...

@topic.articles.build

... et créez 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 l'éditeur de liens, ce qui est génial. Maintenant pour ma question: Mon modèle Linker a aussi des attributs que je veux pouvoir changer via le "nouveau sujet" forme. Mais l'éditeur de liens que Rails crée automatiquement a des valeurs nulles pour tous ses attributs sauf topic_id et article_id. Comment puis-je mettre des champs pour ces autres attributs de l'éditeur de liens dans le formulaire "nouveau sujet" afin qu'ils ne le fassent pas sortir nul?

103
Arcolye

Compris la réponse. L'astuce était:

@topic.linkers.build.build_article

Cela crée les éditeurs de liens, puis crée l'article pour chaque éditeur de liens. Donc, dans les modèles:
topic.rb a besoin de accepts_nested_attributes_for :linkers
linker.rb a besoin de accepts_nested_attributes_for :article

Puis sous la forme:

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

Lorsque le formulaire généré par Rails est soumis au Rails controller#action, le params aura une structure similaire à celle-ci (certains attributs composé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 un Hash indexé zéro avec des touches String, et non un Array? Eh bien, c'est parce que les clés de champ de formulaire 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:

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

Un GOTCHA rapide pour l'utilisation de has_one dans votre solution. Je vais juste copier-coller la réponse donnée par l'utilisateur KandadaBogg dans ce fil .


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

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

La syntaxe de génération pour has_many association:

user.messages.build

La syntaxe de génération pour has_one association:

user.build_profile  # this will work

user.profile.build  # this will throw error

Lis le has_one association documentation pour plus de détails.

3
8bithero