2010-01-09 23 views
106

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. He definido un recurso anidado de la siguiente manera:form_for con recursos anidados

map.resources :articles do |articles| 
    articles.resources :comments 
end 

los comentarios están en la vista show.html.erb para los artículos, por debajo del propio artículo, por ejemplo a esto:

<%= render :partial => "articles/article" %> 
<% form_for([ :article, @comment]) do |f| %> 
    <%= f.text_area :text %> 
    <%= submit_tag "Submit" %> 
<% end %> 

Este da un error, "Identificación llamada por nulo, que erróneamente, etc." También he intentado

<% form_for @article, @comment do |f| %> 

que hace correctamente, pero se refiere a f.text_area campo 'texto' del artículo en lugar de la observación de, y presenta el html para el atributo article.text en esa á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!

Respuesta

207

Travis R es correcto. (Ojalá pudiera votarte). Acabo de hacer esto yo mismo. Con estas rutas:

resources :articles do 
    resources :comments 
end 

Se obtiene como caminos:

/articles/42 
/articles/42/comments/99 

enrutados a los controladores en

app/controllers/articles_controller.rb 
app/controllers/comments_controller.rb 

tal como lo 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| %> 

más importante, si quieres un URI, es posible que tenga algo como esto:

article_comment_path(@article, @comment) 

alternativa:

[@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 suppli ed para la iteración,

<%= link_to "delete", article_comment_path(@article, comment_item), 
     :method => :delete, :confirm => "Really?" %> 

Lo Jamuraa dice que puede funcionar en el contexto del artículo, pero no funcionó para mí en varias otras maneras.

Hay mucha discusión relacionada con los recursos anidados, p. Ej. http://weblog.jamisbuck.org/2007/2/5/nesting-resources

Curiosamente, me acabo de enterar de que la mayoría de las pruebas unitarias de las personas no están probando todas las rutas. Cuando las personas siguen la sugerencia de jamisbuck, terminan con dos formas de obtener recursos anidados. Sus unidad de pruebas por lo general GET/POST a la más simple:

# POST /comments 
post :create, :comment => {:article_id=>42, ...} 

Con el fin de probar la ruta que ellos prefieran, tienen que hacerlo de esta manera:

# POST /articles/42/comments 
post :create, :article_id => 42, :comment => {...} 

Aprendí esto porque mi unidad de pruebas empezaron 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 de unidad. (?. ¿Por qué prueba porque incluso si el usuario nunca ve los duplicados, sus formas pueden referirse a ellos, ya sea implícita o por medio de 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 

Lo siento por la respuesta larga. Creo que no mucha gente conoce las sutilezas.

+0

Es trabajo pero, tuve que modificar el controlador como dijo jamuraa. –

+0

La manera de atasco funciona, pero puede terminar con rutas adicionales que probablemente desconozca. Es mejor ser explícito. – cdunn2001

+0

Tenía recursos anidados, @result inside @course. Sin embargo, '[@result, @course]' funcionó, pero 'form_for (@result, url: {action:" create "})' también funciona.Esto solo necesita el último nombre de modelo y el nombre del método. – Anwar

33

No necesita hacer cosas especiales en el formulario. Usted acaba de construir el comentario correctamente en la acción show:

class ArticlesController < ActionController::Base 
    .... 
    def show 
    @article = Article.find(params[:id]) 
    @new_comment = @article.comments.build 
    end 
    .... 
end 

y luego hacer un formulario para que en el visor de artículos:

<% form_for @new_comment do |f| %> 
    <%= f.text_area :text %> 
    <%= f.submit "Post Comment" %> 
<% end %> 

por defecto, este comentario se destinará a la acción create de CommentsController , en la que probablemente desee poner redirect :back para que se enrute a la página Article.

+9

Tuve que usar el formato 'form_for ([@ article, @new_comment])'. Creo que esto se debe a que estoy mostrando la vista para 'comments # new', not' article # new_comment'. Me imagino en 'article # new_comment' Rails es lo suficientemente inteligente como para averiguar en qué está anidado el objeto de comentario y así no tienes que especificarlo? – Soup

51

estar seguro de tener ambos objetos creados en el controlador: @post y @comment para el cargo, por ejemplo:

@post = Post.find params[:post_id] 
@comment = Comment.new(:post=>@post) 

Luego, en vista:

<%= form_for([@post, @comment]) do |f| %> 

Asegúrese de definir explícitamente la matriz en el form_for, no solo coma separada como lo has hecho anteriormente.

+0

La versión de Travis es un poco vieja, pero creo que es la más correcta para Rails 3.2.X. Si desea que todos los elementos del generador de formularios llenen los campos de Comentario, solo use una matriz, los ayudantes de url no son necesarios. – Karl

+1

Solo establece el objeto principal donde está anidada la acción. Si solo anida parcialmente el recurso (por ejemplo, como en el ejemplo), al configurar el objeto padre se causará que form_for falle (reconfirmado con rails 5.1 en este momento) – iheggie

Cuestiones relacionadas