ruby-on-rails - fields - rails form_for vs form_with
form_for con recursos anidados (3)
Tengo una pregunta de dos partes sobre form_for y los recursos anidados. Digamos que estoy escribiendo un motor de blog y quiero relacionar un comentario con un artículo. Definí un recurso anidado de la siguiente manera:
map.resources :articles do |articles|
articles.resources :comments
end
El formulario de comentarios se encuentra en la vista show.html.erb para artículos, debajo del artículo en sí, por ejemplo, como este:
<%= render :partial => "articles/article" %>
<% form_for([ :article, @comment]) do |f| %>
<%= f.text_area :text %>
<%= submit_tag "Submit" %>
<% end %>
Esto da un error, "Identificación llamada para nulo, que erróneamente, etc." También intenté
<% form_for @article, @comment do |f| %>
Que se representa correctamente pero relaciona f.text_area con el campo ''texto'' del artículo en lugar de los comentarios, y presenta el html para el atributo article.text en ese área de texto. Así que parezco tener esto mal también. Lo que quiero es un formulario cuyo ''enviar'' llamará a create action en CommentsController, con un article_id en los params, por ejemplo, una solicitud posterior a / articles / 1 / comments.
La segunda parte de mi pregunta es, ¿cuál es la mejor manera de crear la instancia de comentario para empezar? Estoy creando un @comment en la acción de mostrar de ArticlesController, por lo que un objeto de comentario estará en el alcance de form_for helper. Luego, en la acción create del CommentsController, creo un nuevo comentario utilizando los parámetros pasados desde form_for.
¡Gracias!
Asegúrese de tener ambos objetos creados en el controlador: @post
y @comment
para la publicación, por ejemplo:
@post = Post.find params[:post_id]
@comment = Comment.new(:post=>@post)
Entonces a la vista:
<%= form_for([@post, @comment]) do |f| %>
Asegúrese de definir explícitamente la matriz en form_for, no solo coma separada como lo hizo anteriormente.
No necesita hacer cosas especiales en el formulario. Usted acaba de construir el comentario correctamente en la acción de mostrar:
class ArticlesController < ActionController::Base
....
def show
@article = Article.find(params[:id])
@new_comment = @article.comments.build
end
....
end
y luego hacer un formulario para ello en la vista del artículo:
<% form_for @new_comment do |f| %>
<%= f.text_area :text %>
<%= f.submit "Post Comment" %>
<% end %>
de forma predeterminada, este comentario irá a la acción de create
de CommentsController
, que luego probablemente quiera redirect :back
para que vuelva a la página Article
.
Travis R es correcto. (Ojalá pudiera votarte). Acabo de hacer esto yo mismo. Con estas rutas:
resources :articles do
resources :comments
end
Obtienes caminos como:
/articles/42
/articles/42/comments/99
enrutado a los controladores en
app/controllers/articles_controller.rb
app/controllers/comments_controller.rb
tal como dice en http://guides.rubyonrails.org/routing.html#nested-resources , sin espacios de nombres especiales.
Pero los parciales y las formas se vuelven complicadas. Tenga en cuenta los corchetes:
<%= form_for [@article, @comment] do |f| %>
Lo más importante, si desea un URI, puede necesitar algo como esto:
article_comment_path(@article, @comment)
Alternativamente:
[@article, @comment]
como se describe en http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects
Por ejemplo, dentro de una colección parcial con comment_item
suministrado para la iteración,
<%= link_to "delete", article_comment_path(@article, comment_item),
:method => :delete, :confirm => "Really?" %>
Lo que dice jamuraa puede funcionar en el contexto del Artículo, pero no funcionó para mí de varias otras maneras.
Hay una gran cantidad de discusiones relacionadas con los recursos anidados, por ejemplo, http://weblog.jamisbuck.org/2007/2/5/nesting-resources
Curiosamente, aprendí que las pruebas unitarias de la mayoría de las personas no están probando todos los caminos. Cuando las personas siguen la sugerencia de jamisbuck, terminan con dos formas de obtener recursos anidados. Sus pruebas unitarias generalmente llegarán / publicarán al más simple:
# POST /comments
post :create, :comment => {:article_id=>42, ...}
Para probar la ruta que prefieran, deben hacerlo de esta manera:
# POST /articles/42/comments
post :create, :article_id => 42, :comment => {...}
Aprendí esto porque mis pruebas unitarias comenzaron a fallar cuando cambié de esto:
resources :comments
resources :articles do
resources :comments
end
a esto:
resources :comments, :only => [:destroy, :show, :edit, :update]
resources :articles do
resources :comments, :only => [:create, :index, :new]
end
Supongo que está bien tener rutas duplicadas y perder algunas pruebas unitarias. (¿Por qué probar? Porque incluso si el usuario nunca ve los duplicados, sus formularios pueden referirse a ellos, ya sea implícitamente o mediante rutas con nombre.) Sin embargo, para minimizar la duplicación innecesaria, recomiendo esto:
resources :comments
resources :articles do
resources :comments, :only => [:create, :index, :new]
end
Perdón por la respuesta larga. Creo que no mucha gente conoce las sutilezas.