Search code examples
ruby-on-railsrspecrspec-rails

RSpec-rails | Description of Finding an Associated Model


How can I describe of finding an associated model in the RSpec-rails controller examples?

I try the following:

Article

class Article < ActiveRecord::Base
  has_many :comments
end

Comment

class Comment < ActiveRecord::Base
end

CommentsControllerSpec

describe CommentsController do
  describe 'update' do
    let(:article) { stub_model Article }
    let(:comment) { stub_model Comment }

    before { Article.stub(:find) { article } }
    before { article.stub(:comments) { [comment] } }

    it 'finds a comment' do
      article.comments.should_receive(:find) { comment }
      put :update, article_id: article.id, id: comment.id
    end
  end
end

CommentsController

class CommentsController < ApplicationController
  def update
    Article.find.comments.find
  end
end

But unfortunatelly it doesn't work. Any ideas?

Thanks.


Solution

  • I tackled the problem by myself.

    Here's the approximate list of actions to describe of finding an associated model in the Rails' controllers.

    1.

    describe CommentsController do
      describe 'update' do
      end
    end
    

    2.

    describe CommentsController do
      describe 'update' do
        it 'finds an article' # <=
      end
    end
    

    3.

    describe CommentsController do
      describe 'update' do
        it 'finds an article' do
          Article.should_receive(:find) # <=
          put :update                   # <=
        end
      end
    end
    

    4.

    No route matches {:controller=>"comments", :action=>"update"}
    

    5.

    describe CommentsController do
      describe 'update' do
        let(:article) { stub_model Article } # <=
    
        it 'finds a article' do
          Article.should_receive(:find)
          put :update, article_id: article.id # <=
        end
      end
    end
    

    6.

    No route matches \
      {:article_id=>"1025", :controller=>"comments", :action=>"update"}
    

    7.

    describe CommentsController do
      describe 'update' do
        let(:article) { stub_model Article }
        let(:comment) { stub_model Comment } # <=
    
        it 'finds an article' do
          Article.should_receive(:find)
          put :update, article_id: article.id, id: comment.id # <=
        end
      end
    end
    

    8.

    (<Article (class)>).find(any args)
           expected: 1 time
           received: 0 times
    

    9.

    class CommentsController < ApplicationController
      def update
        Article.find
      end
    end
    

    10.

    Success!
    

    11.

    describe CommentsController do
      describe 'update' do
        let(:article) { stub_model Article }
        let(:comment) { stub_model Comment }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) # <=
          put :update, article_id: article.id, id: comment.id
        end
      end
    end
    

    12.

    <Article (class)> received :find with unexpected arguments
      expected: ("1025")
           got: (no args)
    

    13.

    class CommentsController < ApplicationController
      def update
        Article.find(params[:article_id]) # <=
      end
    end
    

    14.

    Success!
    

    15.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {                                    # <=
          mock(ActiveRecord::Associations::HasManyAssociation) # <=
        }                                                      # <=
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s)
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do                               # <=
          article.stub(:comments) { association }             # <=
          association.should_receive(:find)                   # <=
          put :update, article_id: article.id, id: comment.id # <=
        end                                                   # <=
      end
    end
    

    16.

    Couldn't find Article with id=1027
    

    17.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          mock(ActiveRecord::Associations::HasManyAssociation)
        }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s)
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article } # <=
          article.stub(:comments) { association }
          association.should_receive(:find)
          put :update, article_id: article.id, id: comment.id
        end
      end
    end
    

    18.

    (Mock ActiveRecord::Associations::HasManyAssociation).find(any args)
        expected: 1 time
        received: 0 times
    

    19.

    class CommentsController < ApplicationController
      def update
        Article.find(params[:article_id]).comments.find # <=
      end
    end
    

    20.

    update
      finds an article (fail!)
      finds a comment  (success!)
    
    undefined method `comments' for nil:NilClass
    

    21.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          mock(ActiveRecord::Associations::HasManyAssociation)
        }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) { article } # <=
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article }
          article.stub(:comments) { association }
          association.should_receive(:find)
          put :update, article_id: article.id, id: comment.id
        end
      end
    end
    

    22.

    update
      finds an article (fail!)
      finds a comment  (success!)
    
    Couldn't find Comment without an ID
    

    23.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          mock(ActiveRecord::Associations::HasManyAssociation)
        }
    
        before { article.stub(:comments) { association } } # <=
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) { article }
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article }
          # -> article.stub(:comments) { association } <-
          association.should_receive(:find)
          put :update, article_id: article.id, id: comment.id
        end
      end
    end
    

    24.

    update
      finds an article (fail!)
      finds a comment  (success!)
    
    Mock ActiveRecord::Associations::HasManyAssociation \
      received unexpected message :find with (no args)
    

    25.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          mock(ActiveRecord::Associations::HasManyAssociation).as_null_object # <=
        }
    
        before { article.stub(:comments) { association } }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) { article }
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article }
          association.should_receive(:find)
          put :update, article_id: article.id, id: comment.id
        end
      end
    end
    

    26.

    Success!
    

    27.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          mock(ActiveRecord::Associations::HasManyAssociation).as_null_object
        }
    
        before { article.stub(:comments) { association } }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) { article }
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article }
          association.should_receive(:find).with(comment.id.to_s) # <=
          put :update, article_id: article.id, id: comment.id
        end
      end
    end
    

    28.

    Mock ActiveRecord::Associations::HasManyAssociation \
      received :find with unexpected arguments
      expected: ("1028")
           got: (no args)
    

    29.

    class CommentsController < ApplicationController
      def update
        Article.find(params[:article_id]).comments.find(params[:id]) # <=
      end
    end
    

    30.

    Success!
    

    31.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          double(ActiveRecord::Associations::HasManyAssociation).as_null_object # <=
        }
    
        before { article.stub(:comments) { association } }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) { article }
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article }
          association.should_receive(:find).with(comment.id.to_s)
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'assigns @comment' do                              # <=
          Article.stub(:find) { article }                     # <=
          association.stub(:find) { comment }                 # <=
          put :update, article_id: article.id, id: comment.id # <=
          assigns[:comment].should eq comment                 # <=
        end                                                   # <=
      end
    end
    

    32.

    expected: #<Comment >
         got: nil
    

    33.

    class CommentsController < ApplicationController
      def update
        @comment = Article.find(params[:article_id]).comments.find(params[:id]) # <=
      end
    end
    

    34.

    Success!
    

    35.

    describe CommentsController do
      describe 'update' do
        let(:article)     { stub_model Article }
        let(:comment)     { stub_model Comment }
        let(:association) {
          double(ActiveRecord::Associations::HasManyAssociation).as_null_object
        }
    
        before { article.stub(:comments) { association } }
    
        it 'finds an article' do
          Article.should_receive(:find).with(article.id.to_s) { article }
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'finds a comment' do
          Article.stub(:find) { article }
          association.should_receive(:find).with(comment.id.to_s)
          put :update, article_id: article.id, id: comment.id
        end
    
        it 'assigns @article' do                              # <=
          Article.stub(:find) { article }                     # <=
          put :update, article_id: article.id, id: comment.id # <=
          assigns[:article].should eq article                 # <=
        end                                                   # <=
    
        it 'assigns @comment' do
          Article.stub(:find) { article }
          association.stub(:find) { comment }
          put :update, article_id: article.id, id: comment.id
          assigns[:comment].should eq comment
        end
      end
    end
    

    36.

    expected: #<Article >
         got: nil
    

    37.

    class CommentsController < ApplicationController
      def update
        @article = Article.find(params[:article_id])   # <=
        @comment = @article.comments.find(params[:id]) # <=
      end
    end
    

    38.

    Success!
    

    39.

    class CommentsController < ApplicationController
      before_filter :find_article, only: :update # <=
      before_filter :find_comment, only: :update # <=
    
      def update
        # -> @article = Article.find(params[:article_id])   <-
        # -> @comment = @article.comments.find(params[:id]) <-
      end
    
      private                                          # <=
        def find_article                               # <=
          @article = Article.find(params[:article_id]) # <=
        end                                            # <=
    
        def find_comment                                 # <=
          @comment = @article.comments.find(params[:id]) # <=
        end                                              # <=
    end
    

    40.

    Success!