ruby-on-rails - anidados - rails formularios
Rails anidado forma con has_many: a través de, cómo editar los atributos de modelo de unión? (3)
¿Cómo se editan los atributos de un modelo de unión cuando se utiliza accept_nested_attributes_for?
Tengo 3 modelos: temas y artículos unidos por 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
Entonces cuando construyo el artículo en la "nueva" acción del controlador de temas ...
@topic.articles.build
... y hacer la forma anidada en topics / new.html.erb ...
<% form_for(@topic) do |topic_form| %>
...fields...
<% topic_form.fields_for :articles do |article_form| %>
...fields...
... Rails crea automáticamente el enlazador, que es genial. Ahora, para mi pregunta: el modelo My Linker también tiene atributos que deseo poder cambiar a través del formulario "nuevo tema". Pero el enlazador que Rails crea automáticamente tiene valores nulos para todos sus atributos, excepto topic_id y article_id. ¿Cómo puedo poner campos para esos otros atributos del enlazador en el formulario "nuevo tema" para que no salgan?
Cuando el formulario generado por Rails se envía a la controller#action
Rails, los params
tendrán una estructura similar a esta (se agregaron algunos atributos):
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."
}
}
}
}
}
Observe cómo linkers_attributes
es en realidad un Hash
índice cero con las teclas String
, y no una Array
? Bueno, esto se debe a que las claves de campo de formulario que se envían al servidor se ven así:
topic[name]
topic[linkers_attributes][0][is_active]
topic[linkers_attributes][0][article_attributes][title]
Crear el registro ahora es tan simple como:
TopicController < ApplicationController
def create
@topic = Topic.create!(params[:topic])
end
end
Encontré la respuesta. El truco fue:
@topic.linkers.build.build_article
Eso construye los enlazadores, luego construye el artículo para cada enlazador. Entonces, en los modelos:
topic.rb necesita accepts_nested_attributes_for :linkers
linker.rb necesita accepts_nested_attributes_for :article
Luego en la 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...
Un GOTCHA rápido para cuando uses has_one en tu solución. KandadaBoggu y KandadaBoggu la respuesta dada por el usuario KandadaBoggu en este hilo .
La firma del método de build
es diferente para has_one
y has_one
asociaciones.
class User < ActiveRecord::Base
has_one :profile
has_many :messages
end
La sintaxis de compilación para la asociación has_many
:
user.messages.build
La sintaxis de has_one
para la asociación has_one
:
user.build_profile # this will work
user.profile.build # this will throw error
Lea la documentation asociación has_one
para más detalles.