title: RSpec test for create action of a controller for a nested resource
body: <p>I have a Rails application (Rails 3.0.10) where users can have many articles, and where the users can leave comments on the articles. Comments are made on the article show page. </p>
  
  <p>Now I want to test the create action of the CommentsController, however, I have problems of invoking the post method with the right parameters. </p>
  
  <p>Here's the code of the CommentsController:</p>
  
  <pre><code>class CommentsController &lt; ApplicationController
  
    # create a comment and bind it to an article and a user  
    def create
      @article = Article.find(params[:article_id])
      @user = User.find(@article.user_id)
      @comment = @article.comments.build(params[:comment])
      @comment.user_id = current_user.id
  
      commenters = [] 
      @article.comments.each {
        |comment|
        commenters &lt;&lt; User.find(comment.user_id)
      }
      commenters.uniq!
  
      respond_to do |format|
        if @comment.save        
  
          #Notify user who offers article on new comment, else notify the commenters
          if @article.user_id != @comment.user_id
            UserMailer.new_article_comment_email(@user, @comment).deliver
          else        
            commenters.each {
              |commenter|
              UserMailer.new_article_comment_email(commenter, @comment).deliver
            }
          end
  
          format.html { 
            redirect_to(@article)
            flash[:notice] = t(:comment_create_success)
          }
        else
          format.html { 
            redirect_to(@article) 
            flash[:error] = t(:comment_create_error)
          }
        end
      end
    end
  end
  </code></pre>
  
  <p>The RSpec code for testing this action (some experiments so far) is the following: </p>
  
  <pre><code>require 'spec_helper'
  require 'ruby-debug'
  
  describe CommentsController do
    render_views
  
    describe "POST 'create'" do
  
      before(:each) do
        @user = FactoryGirl.create(:user)
  
        @article = FactoryGirl.build(:article)
        @article.user_id = @user.id
        @article.save
  
        @article_attributes = FactoryGirl.attributes_for(:article)
        @comment_attributes = FactoryGirl.attributes_for(:comment)
      end
  
      it "should create a new comment" do
        expect {
          post :create, :comment =&gt; @comment_attributes
        }.to change(Comment, :count).by(1)
      end
  
      it "should create a new comment, redirect to the article show page of this comment and notify the user on successful saving of the comment" do
        post :create, :comment =&gt; @comment_attributes, :article_id =&gt; @article.id.to_s, :user_id =&gt; @user.id.to_s
        flash[:notice].should_not be_nil
        response.should redirect_to(article_path(@article))
      end
  
    end
  
  end
  </code></pre>
  
  <p>Both tests fail, however, due to different reasons that I am unable to fix:</p>
  
  <pre><code>    Failures:
  
        1) CommentsController POST 'create' should create a new comment
           Failure/Error: post :create, :comment =&gt; @comment_attributes
           ActionController::RoutingError:
             No route matches {:comment=&gt;{:body=&gt;"This is the body text of a comment"}, :controller=&gt;"comments", :action=&gt;"create"}
           # ./spec/controllers/comments_controller_spec.rb:22:in `block (4 levels) in &lt;top (required)&gt;'
           # ./spec/controllers/comments_controller_spec.rb:21:in `block (3 levels) in &lt;top (required)&gt;'
  
        2) CommentsController POST 'create' should create a new comment, redirect to the article show page of this comment and notify the user on successful saving of the comment
           Failure/Error: post :create, :comment =&gt; @comment_attributes, :article_id =&gt; @article.id.to_s, :user_id =&gt; @user.id.to_s
           RuntimeError:
             Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
           # ./app/controllers/comments_controller.rb:8:in `create'
           # ./spec/controllers/comments_controller_spec.rb:27:in `block (3 levels) in &lt;top (required)&gt;'
  </code></pre>
  
  <p>I would be great if someone could help me out. Thanks in advance!</p>
  
  <p>Update: Here's the routes.rb I am using:</p>
  
  <pre><code>Cinderella::Application.routes.draw do
  
    # The priority is based upon order of creation:
    # first created -&gt; highest priority.
  
    # Sample of regular route:
    #   match 'products/:id' =&gt; 'catalog#view'
    # Keep in mind you can assign values other than :controller and :action
  
    # Sample of named route:
    #   match 'products/:id/purchase' =&gt; 'catalog#purchase', :as =&gt; :purchase
    # This route can be invoked with purchase_url(:id =&gt; product.id)  
  
    match '/signup',  :to =&gt; 'users#new'
    match '/signin',  :to =&gt; 'sessions#new'
    match '/signout',  :to =&gt; 'sessions#destroy'
  
    match '/home', :to =&gt; 'pages#home'
    match '/about',   :to =&gt; 'pages#about'
    match '/faq', :to =&gt; 'pages#faq'
    match '/howitworks_sellers', :to =&gt; "pages#howitworks_sellers"
    match '/howitworks_buyers', :to =&gt; "pages#howitworks_buyers"
    match '/contact', :to =&gt; 'pages#contact'
  
    match '/articles/:id/ratings', :to =&gt; 'ratings#destroy'
  
    # Sample resource route (maps HTTP verbs to controller actions automatically):
    #   resources :products
  
    resources :articles do
      resources :comments, :only =&gt; [:create, :destroy]
    end
  
    resources :ratings
    resources :ratings do
      collection do
        post 'destroy'
      end
    end
  
    resources :users do
      resources :articles
    end
  
    resources :sessions, :only =&gt; [:new, :create, :destroy]
  
    # Sample resource route with options:
    #   resources :products do
    #     member do
    #       get 'short'
    #       post 'toggle'
    #     end
    #
    #     collection do
    #       get 'sold'
    #     end
    #   end
  
    # Sample resource route with sub-resources:
    #   resources :products do
    #     resources :comments, :sales
    #     resource :seller
    #   end
  
    # Sample resource route with more complex sub-resources
    #   resources :products do
    #     resources :comments
    #     resources :sales do
    #       get 'recent', :on =&gt; :collection
    #     end
    #   end
  
    # Sample resource route within a namespace:
    #   namespace :admin do
    #     # Directs /admin/products/* to Admin::ProductsController
    #     # (app/controllers/admin/products_controller.rb)
    #     resources :products
    #   end
  
    # You can have the root of your site routed with "root"
    # just remember to delete public/index.html.
    root :to =&gt; "pages#home"
  
    # See how all your routes lay out with "rake routes"
  
    # This is a legacy wild controller route that's not recommended for RESTful applications.
    # Note: This route will make all actions in every controller accessible via GET requests.
    # match ':controller(/:action(/:id(.:format)))'
  end
  #== Route Map
  # Generated on 14 Dec 2011 14:24
  #
  #            signin        /signin(.:format)                           {:controller=&gt;"sessions", :action=&gt;"new"}
  #           signout        /signout(.:format)                          {:controller=&gt;"sessions", :action=&gt;"destroy"}
  #              home        /home(.:format)                             {:controller=&gt;"pages", :action=&gt;"home"}
  #             about        /about(.:format)                            {:controller=&gt;"pages", :action=&gt;"about"}
  #               faq        /faq(.:format)                              {:controller=&gt;"pages", :action=&gt;"faq"}
  #          articles GET    /articles(.:format)                         {:action=&gt;"index", :controller=&gt;"articles"}
  #                   POST   /articles(.:format)                         {:action=&gt;"create", :controller=&gt;"articles"}
  #       new_article GET    /articles/new(.:format)                     {:action=&gt;"new", :controller=&gt;"articles"}
  #      edit_article GET    /articles/:id/edit(.:format)                {:action=&gt;"edit", :controller=&gt;"articles"}
  #           article GET    /articles/:id(.:format)                     {:action=&gt;"show", :controller=&gt;"articles"}
  #                   PUT    /articles/:id(.:format)                     {:action=&gt;"update", :controller=&gt;"articles"}
  #                   DELETE /articles/:id(.:format)                     {:action=&gt;"destroy", :controller=&gt;"articles"}
  #     user_articles GET    /users/:user_id/articles(.:format)          {:action=&gt;"index", :controller=&gt;"articles"}
  #                   POST   /users/:user_id/articles(.:format)          {:action=&gt;"create", :controller=&gt;"articles"}
  #  new_user_article GET    /users/:user_id/articles/new(.:format)      {:action=&gt;"new", :controller=&gt;"articles"}
  # edit_user_article GET    /users/:user_id/articles/:id/edit(.:format) {:action=&gt;"edit", :controller=&gt;"articles"}
  #      user_article GET    /users/:user_id/articles/:id(.:format)      {:action=&gt;"show", :controller=&gt;"articles"}
  #                   PUT    /users/:user_id/articles/:id(.:format)      {:action=&gt;"update", :controller=&gt;"articles"}
  #                   DELETE /users/:user_id/articles/:id(.:format)      {:action=&gt;"destroy", :controller=&gt;"articles"}
  #             users GET    /users(.:format)                            {:action=&gt;"index", :controller=&gt;"users"}
  #                   POST   /users(.:format)                            {:action=&gt;"create", :controller=&gt;"users"}
  #          new_user GET    /users/new(.:format)                        {:action=&gt;"new", :controller=&gt;"users"}
  #         edit_user GET    /users/:id/edit(.:format)                   {:action=&gt;"edit", :controller=&gt;"users"}
  #              user GET    /users/:id(.:format)                        {:action=&gt;"show", :controller=&gt;"users"}
  #                   PUT    /users/:id(.:format)                        {:action=&gt;"update", :controller=&gt;"users"}
  #                   DELETE /users/:id(.:format)                        {:action=&gt;"destroy", :controller=&gt;"users"}
  #          sessions POST   /sessions(.:format)                         {:action=&gt;"create", :controller=&gt;"sessions"}
  #       new_session GET    /sessions/new(.:format)                     {:action=&gt;"new", :controller=&gt;"sessions"}
  #           session DELETE /sessions/:id(.:format)                     {:action=&gt;"destroy", :controller=&gt;"sessions"}
  #              root        /(.:format)                                 {:controller=&gt;"pages", :action=&gt;"home"}
  </code></pre>
  
  <p>Update: Here's the modification I did according to nmotts suggestions:</p>
  
  <pre><code>require 'spec_helper'
  require 'ruby-debug'
  
  describe CommentsController do
    render_views
  
    describe "POST 'create'" do
  
      before(:each) do
        @user = FactoryGirl.create(:user)
  
        @article = FactoryGirl.build(:article)
        @article.user_id = @user.id
        @article.save
  
        @comment_attributes = FactoryGirl.attributes_for(:comment, :article_id =&gt; @article)
      end
  
      it "should create a new comment" do
        post :create, :article_id =&gt; @article.id.to_s, :comment =&gt; @comment_attributes
      end
  
    end
  
  end
  </code></pre>
  
  <p>And the FactoryGirl definition for comment:</p>
  
  <pre><code>factory :comment do
    body "This is the body text of a comment"
    article
  end
  </code></pre>
  
  <p>Unfortunately, the code is not yet working. </p>