form_for com resources nesteds

Eu tenho uma pergunta de duas partes sobre form_for e resources nesteds. Digamos que estou escrevendo um mecanismo de blog e quero relacionar um comentário a um artigo. Eu defini um recurso nested da seguinte maneira:

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

O formulário de comentários está na visualização show.html.erb para artigos, abaixo do próprio artigo, por exemplo, como este:

  "articles/article" %>     

Isso dá um erro “, chamado id para nil, o que seria erroneamente etc.” Eu também tentei

  

Que processa corretamente mas relaciona f.text_area ao campo ‘text’ do artigo em vez do comentário, e apresenta o html para o atributo article.text nessa área de texto. Então eu pareço ter isso errado também. O que eu quero é um formulário cujo ‘submit’ irá chamar a action create no CommentsController, com um article_id nos params, por exemplo um post request para / articles / 1 / comments.

A segunda parte da minha pergunta é: qual é a melhor maneira de criar a instância de comentário para começar? Estou criando um @comment na ação show do ArticlesController, portanto, um object de comentário estará no escopo do form_for helper. Então, na ação create do CommentsController, eu crio new @comment usando os parâmetros passados ​​do form_for.

Obrigado!

Travis R está correto. (Eu gostaria de poder te vingar.) Eu acabei de fazer isso funcionar sozinho. Com estas rotas:

 resources :articles do resources :comments end 

Você obtém caminhos como:

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

encaminhado para controladores em

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

como diz em http://guides.rubyonrails.org/routing.html#nested-resources , sem namespaces especiais.

Mas parciais e formas se tornam complicadas. Observe os colchetes:

 <%= form_for [@article, @comment] do |f| %> 

O mais importante, se você quiser um URI, pode precisar de algo assim:

 article_comment_path(@article, @comment) 

Alternativamente:

 [@article, @comment] 

conforme descrito em http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects

Por exemplo, dentro de uma coleção parcial com comment_item fornecida para iteração,

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

O que Jamuraa diz pode funcionar no contexto do artigo, mas não funcionou para mim de várias outras maneiras.

Há muita discussão relacionada a resources nesteds, por exemplo, http://weblog.jamisbuck.org/2007/2/5/nesting-resources

Curiosamente, acabei de aprender que os testes unitários da maioria das pessoas não estão realmente testando todos os caminhos. Quando as pessoas seguem a sugestão de Jamies, acabam com duas maneiras de obter resources nesteds. Seus testes unitários geralmente são enviados para o mais simples:

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

Para testar a rota que eles podem preferir, eles precisam fazer isso da seguinte maneira:

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

Eu aprendi isso porque meus testes de unidade começaram a falhar quando eu mudei isso:

 resources :comments resources :articles do resources :comments end 

para isso:

 resources :comments, :only => [:destroy, :show, :edit, :update] resources :articles do resources :comments, :only => [:create, :index, :new] end 

Eu acho que é ok ter rotas duplicadas e perder alguns testes unitários. (Por que testar? Porque, mesmo que o usuário nunca veja as duplicatas, seus formulários podem se referir a eles, seja implicitamente ou por meio de rotas nomeadas.) Ainda assim, para minimizar a duplicação desnecessária, recomendo o seguinte:

 resources :comments resources :articles do resources :comments, :only => [:create, :index, :new] end 

Desculpe pela longa resposta. Muitas pessoas não estão conscientes das sutilezas, eu acho.

Certifique-se de ter ambos os objects criados no controller: @comment e @comment para o post, por exemplo:

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

Então em vista:

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

Certifique-se de definir explicitamente o array no form_for, não apenas com vírgulas separadas como você tem acima.

Você não precisa fazer coisas especiais no formulário. Você acabou de criar o comentário corretamente na ação de exibição:

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

e, em seguida, crie um formulário para ele na visualização do artigo:

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

Por padrão, este comentário irá para a ação de create de CommentsController , que você provavelmente irá querer colocar o redirect :back para o que você está encaminhado de volta para a página do Article .

Intereting Posts