Using Rails default exception translation in specs

2019-08-04 15:09发布

问题:

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?

回答1:

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