Search code examples
ruby-on-rails-3.2rspec2rspec-rails

Using Rails default exception translation in specs


My controller is throwing ActiveRecord::RecordNotFound which is what to be expected to be translated into 404.

Now I want to test this behaviour in my controller spec, but it gets exception rather than response_code equal to 404. How to make it get this code instead?


Solution

  • When Rails raise a ActiveRecord::RecordNotFound it simply telling you that ActiveRecord was not able to find a resource in your database (usually using find).

    It is your responsability to catch the exception and to do whatever you want to do (in your case return a 404 not found http error).

    A simple implementation to illustrate the above is by doing the following:

    app/controllers/application_controller.rb

    class ApplicationController < ActionController::Base
      protect_from_forgery
    
      rescue_from ActiveRecord::RecordNotFound, with: :not_found
    
      private
    
      def not_found
        render file: 'public/404.html', status: 404, layout: false
      end
    end
    

    This way every time rails will throw a ActiveRecord::RecordNotFound from any controllers that inherit from ApplicationController, it will be rescued and render the 404 rails default page located at public/404.html

    Now, in order to test this:

    spec/controllers/application_controller_spec.rb

    require 'spec_helper'
    
    describe ApplicationController do
    
      describe "ActiveRecord::RecordNotFound exception" do
    
        controller do
          def index
            raise ActiveRecord::RecordNotFound.new('')
          end
        end
    
        it "calls not_found private method" do
          expect(controller).to receive(:not_found)
          get :index
        end
    
      end
    
    end
    

    You will need to add the following in your spec/spec_helper.rb

    config.infer_base_class_for_anonymous_controllers = true