1. ホーム
  2. ruby-on-rails

[解決済み] ネストされたリソースを持つ form_for

2022-07-19 01:59:29

質問

form_forとネストされたリソースについて、2つのパートからなる質問があります。例えば、私がブログエンジンを書いていて、コメントを記事に関連づけたいとします。私は以下のようにネストされたリソースを定義しました。

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

コメントフォームは、記事用のshow.html.erbのビューで、記事自体の下に、例えばこのようにあります。

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

これは、 "Called id for nil, which would mistakenly etc." というエラーを出します。

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

これは正しく表示されますが、f.text_areaをコメントではなく記事の'text'フィールドに関連付け、そのテキストエリアにarticle.text属性用のhtmlを表示します。というわけで、これも間違っているようです。私が欲しいのは、commentsController の create アクションを呼び出すフォームの 'submit' で、params に article_id を指定し、例えば /articles/1/comments に post リクエストをするものです。

質問の第二は、そもそもコメントインスタンスを作成するのに最適な方法は何なのかということです。私はArticlesControllerのshowアクションで@commentを作成し、コメントオブジェクトがform_forヘルパーのスコープになるようにしています。それから CommentsController の create アクションで、form_for から渡されたパラメータを使用して新しい @comment を作成します。

ありがとうございます!

どのように解決するのですか?

Travis Rは正しいです。(upvoteできればいいのですが。) 私はちょうどこれを自分で動かすことができました。これらのルートで。

resources :articles do
  resources :comments
end

のようなパスが得られます。

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

にあるコントローラにルーティングされます。

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

に書いてあるように http://guides.rubyonrails.org/routing.html#nested-resources で、特別な名前空間はありません。

しかし、部分とフォームが厄介なことになります。角括弧に注意してください。

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

最も重要なのは、URIが必要な場合、このようなものが必要な場合があります。

article_comment_path(@article, @comment)

あるいは

[@article, @comment]

で説明したように http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects

例えば、コレクションパーシャルの内部で comment_item が繰り返しのために提供されています。

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

jamuraaさんのおっしゃることは、Articleの文脈では有効かもしれませんが、他の様々な点では私にはうまくいきませんでした。

ネストされたリソースに関連する多くの議論があります、例えば http://weblog.jamisbuck.org/2007/2/5/nesting-resources

興味深いことに、ほとんどの人のユニットテストは、実際にはすべてのパスをテストしていないことを知りました。jamisbuck 氏の提案に従うと、ネストされたリソースを取得する 2 つの方法で終わります。ユニットテストは一般に、最も単純なものを取得/投稿します。

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

彼らが好むかもしれないルートをテストするために、このようにする必要があります。

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

これを切り替えたらユニットテストが失敗するようになったので覚えました。

resources :comments
resources :articles do
  resources :comments
end

をこれに変更します。

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

ルートが重複していても、ユニットテストが少なくても大丈夫なんでしょうね。(なぜテストするのでしょうか?なぜなら、ユーザーが重複を見ることがなくても、フォームが暗黙のうちに、もしくは名前つきのルートを通して、それらを参照する可能性があるからです)。それでも、不要な重複を最小限にするために、私はこれを推奨します。

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

長い回答で申し訳ありません。微妙に意識している人は少ないと思います。