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?
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...
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
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.