129

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 %>

これにより、「誤って nil の id が呼び出されました」というエラーが発生します。私も試してみました

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

これは正しくレンダリングされますが、コメントではなく記事の「テキスト」フィールドに f.text_area を関連付け、そのテキスト領域に article.text 属性の html を表示します。だから私はこれも間違っているようです。私が欲しいのは、たとえば/articles/1/commentsへの投稿リクエストなど、paramsにarticle_idを使用して、「送信」がCommentsControllerの作成アクションを呼び出すフォームです。

私の質問の 2 番目の部分は、最初にコメント インスタンスを作成する最良の方法は何ですか? ArticlesController の show アクションで @comment を作成しているので、comment オブジェクトは form_for ヘルパーのスコープになります。次に、CommentsController の作成アクションで、form_for から渡されたパラメーターを使用して新しい @comment を作成します。

ありがとう!

4

3 に答える 3

233

トラビスRは正しいです。(私はあなたに賛成できたらいいのにと思います。)私はこれを自分で動かしました。これらのルートで:

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

長い答えでごめんなさい。微妙なことに気づいている人は少ないと思います。

于 2011-01-06T05:08:29.113 に答える
56

コントローラで両方のオブジェクトを作成していることを確認してください。投稿の場合、例@post@comment

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

次に、ビューで:

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

上記のようにコンマで区切るだけでなく、form_forで配列を明示的に定義してください。

于 2010-12-27T07:35:59.557 に答える
35

フォームで特別なことをする必要はありません。show アクションでコメントを正しく作成するだけです。

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

次に、記事ビューでフォームを作成します。

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

デフォルトでは、このコメントは のcreateアクションに送られます。そのページに戻るように、このコメントを挿入しCommentsControllerたいと思うでしょう。redirect :backArticle

于 2010-01-10T00:08:52.133 に答える