Logo: Relish

  1. Sign up
  2. Sign in

Project: RSpec Rails 3.1

anonymous controller

Use the controller method to define an anonymous controller that will
inherit from the described class. This is useful for specifying behavior like
global error handling.

To specify a different base class you can pass the class explicitly to the
controller method:

controller(BaseController)

You can also disable base type inference, in which case anonymous controllers
will inherit from ApplicationController instead of the described class by
default:

RSpec.configure do |c|
  c.infer_base_class_for_anonymous_controllers = false
end

RSpec.describe BaseController do
  controller do
    def index; end

    ​# this normally creates an anonymous `BaseController` subclass, but
    ​# since `infer_base_class_for_anonymous_controllers` is disabled,
    ​# it creates a subclass of `ApplicationController` instead
  end
end
Scenarios
Specify error handling in `ApplicationController`
Given
a file named "spec/controllers/application_controller_spec.rb" with:
require "rails_helper"

class ApplicationController < ActionController::Base
  class AccessDenied < StandardError; end

  rescue_from AccessDenied, :with => :access_denied

private

  def access_denied
    redirect_to "/401.html"
  end
end

RSpec.describe ApplicationController do
  controller do
    def index
      raise ApplicationController::AccessDenied
    end
  end

  describe "handling AccessDenied exceptions" do
    it "redirects to the /401.html page" do
      get :index
      expect(response).to redirect_to("/401.html")
    end
  end
end
When
I run rspec spec
Then
the examples should all pass
Specify error handling in subclass of `ApplicationController`
Given
a file named "spec/controllers/application_controller_subclass_spec.rb" with:
require "rails_helper"

class ApplicationController < ActionController::Base
  class AccessDenied < StandardError; end
end

class ApplicationControllerSubclass < ApplicationController

  rescue_from ApplicationController::AccessDenied, :with => :access_denied

private

  def access_denied
    redirect_to "/401.html"
  end
end

RSpec.describe ApplicationControllerSubclass do
  controller(ApplicationControllerSubclass) do
    def index
      raise ApplicationController::AccessDenied
    end
  end

  describe "handling AccessDenied exceptions" do
    it "redirects to the /401.html page" do
      get :index
      expect(response).to redirect_to("/401.html")
    end
  end
end
When
I run rspec spec
Then
the examples should all pass
Infer base class from the described class
Given
a file named "spec/controllers/base_class_can_be_inferred_spec.rb" with:
require "rails_helper"

class ApplicationController < ActionController::Base; end

class ApplicationControllerSubclass < ApplicationController; end

RSpec.describe ApplicationControllerSubclass do
  controller do
    def index
      render :text => "Hello World"
    end
  end

  it "creates an anonymous controller derived from ApplicationControllerSubclass" do
    expect(controller).to be_a_kind_of(ApplicationControllerSubclass)
  end
end
When
I run rspec spec
Then
the examples should all pass
Use `name` and `controller_name` from the described class
Given
a file named "spec/controllers/get_name_and_controller_name_from_described_class_spec.rb" with:
require "rails_helper"

class ApplicationController < ActionController::Base; end
class FoosController < ApplicationController; end

RSpec.describe "FoosController controller_name" do
  controller FoosController do
    def index
      @name = self.class.name
      @controller_name = controller_name
      render :text => "Hello World"
    end
  end

  before do
    get :index
  end

  it "gets the class name as described" do
    expect(assigns[:name]).to eq('FoosController')
  end

  it "gets the controller_name as described" do
    expect(assigns[:controller_name]).to eq('foos')
  end
end
When
I run rspec spec
Then
the examples should all pass
Invoke `around_filter` and `around_action` in base class
Given
a file named "spec/controllers/application_controller_around_filter_spec.rb" with:
require "rails_helper"

class ApplicationController < ActionController::Base
  around_filter :an_around_filter

  def an_around_filter
    @callback_invoked = true
    yield
  end
end

RSpec.describe ApplicationController do
  controller do
    def index
      render :nothing => true
    end
  end

  it "invokes the callback" do
    get :index

    expect(assigns[:callback_invoked]).to be_truthy
  end
end
When
I run rspec spec
Then
the examples should all pass
Anonymous controllers only create resource routes
Given
a file named "spec/controllers/application_controller_spec.rb" with:
require "rails_helper"

RSpec.describe ApplicationController do
  controller do
    def index
      render :text => "index called"
    end

    def create
      render :text => "create called"
    end

    def new
      render :text => "new called"
    end

    def show
      render :text => "show called"
    end

    def edit
      render :text => "edit called"
    end

    def update
      render :text => "update called"
    end

    def destroy
      render :text => "destroy called"
    end

    def willerror
      render :text => "will not render"
    end
  end

  describe "#index" do
    it "responds to GET" do
      get :index
      expect(response.body).to eq "index called"
    end

    it "also responds to POST" do
      post :index
      expect(response.body).to eq "index called"
    end

    it "also responds to PUT" do
      put :index
      expect(response.body).to eq "index called"
    end

    it "also responds to DELETE" do
      delete :index
      expect(response.body).to eq "index called"
    end
  end

  describe "#create" do
    it "responds to POST" do
      post :create
      expect(response.body).to eq "create called"
    end

    # And the rest...
    %w{get post put delete}.each do |calltype|
      it "responds to #{calltype}" do
        send(calltype, :create)
        expect(response.body).to eq "create called"
      end
    end
  end

  describe "#new" do
    it "responds to GET" do
      get :new
      expect(response.body).to eq "new called"
    end

    # And the rest...
    %w{get post put delete}.each do |calltype|
      it "responds to #{calltype}" do
        send(calltype, :new)
        expect(response.body).to eq "new called"
      end
    end
  end

  describe "#edit" do
    it "responds to GET" do
      get :edit, :id => "anyid"
      expect(response.body).to eq "edit called"
    end

    it "requires the :id parameter" do
      expect { get :edit }.to raise_error(ActionController::RoutingError)
    end

    # And the rest...
    %w{get post put delete}.each do |calltype|
      it "responds to #{calltype}" do
        send(calltype, :edit, {:id => "anyid"})
        expect(response.body).to eq "edit called"
      end
    end
  end

  describe "#show" do
    it "responds to GET" do
      get :show, :id => "anyid"
      expect(response.body).to eq "show called"
    end

    it "requires the :id parameter" do
      expect { get :show }.to raise_error(ActionController::RoutingError)
    end

    # And the rest...
    %w{get post put delete}.each do |calltype|
      it "responds to #{calltype}" do
        send(calltype, :show, {:id => "anyid"})
        expect(response.body).to eq "show called"
      end
    end
  end

  describe "#update" do
    it "responds to PUT" do
      put :update, :id => "anyid"
      expect(response.body).to eq "update called"
    end

    it "requires the :id parameter" do
      expect { put :update }.to raise_error(ActionController::RoutingError)
    end

    # And the rest...
    %w{get post put delete}.each do |calltype|
      it "responds to #{calltype}" do
        send(calltype, :update, {:id => "anyid"})
        expect(response.body).to eq "update called"
      end
    end
  end

  describe "#destroy" do
    it "responds to DELETE" do
      delete :destroy, :id => "anyid"
      expect(response.body).to eq "destroy called"
    end

    it "requires the :id parameter" do
      expect { delete :destroy }.to raise_error(ActionController::RoutingError)
    end

    # And the rest...
    %w{get post put delete}.each do |calltype|
      it "responds to #{calltype}" do
        send(calltype, :destroy, {:id => "anyid"})
        expect(response.body).to eq "destroy called"
      end
    end
  end

  describe "#willerror" do
    it "cannot be called" do
      expect { get :willerror }.to raise_error(ActionController::RoutingError)
    end
  end
end
When
I run rspec spec
Then
the examples should all pass
Draw custom routes for anonymous controllers
Given
a file named "spec/controllers/application_controller_spec.rb" with:
require "rails_helper"

RSpec.describe ApplicationController do
  controller do
    def custom
      render :text => "custom called"
    end
  end

  specify "a custom action can be requested if routes are drawn manually" do
    routes.draw { get "custom" => "anonymous#custom" }

    get :custom
    expect(response.body).to eq "custom called"
  end
end
When
I run rspec spec
Then
the examples should all pass
Draw custom routes for defined controllers
Given
a file named "spec/controllers/application_controller_spec.rb" with:
require "rails_helper"

class FoosController < ApplicationController; end

RSpec.describe ApplicationController do
  controller FoosController do
    def custom
      render :text => "custom called"
    end
  end

  specify "a custom action can be requested if routes are drawn manually" do
    routes.draw { get "custom" => "foos#custom" }

    get :custom
    expect(response.body).to eq "custom called"
  end
end
When
I run rspec spec
Then
the examples should all pass
Works with namespaced controllers
Given
a file named "spec/controllers/namespaced_controller_spec.rb" with:
require "rails_helper"

class ApplicationController < ActionController::Base; end
module TopLevel
  module InnerSpace
    class FoosController < ApplicationController; end
  end
end

RSpec.describe TopLevel::InnerSpace::FoosController do
  controller do
    def index
      @name = self.class.name
      @controller_name = controller_name
      render :text => "Hello World"
    end
  end

  it "creates an anonymous controller derived from the namespace" do
    expect(controller).to be_a_kind_of(TopLevel::InnerSpace::FoosController)
  end

  it "gets the class name as described" do
    expect{ get :index }.to change{ assigns[:name] }.
      to eq('TopLevel::InnerSpace::FoosController')
  end

  it "gets the controller_name as described" do
    expect{ get :index }.to change{ assigns[:controller_name] }.
      to eq('foos')
  end
end
When
I run rspec spec
Then
the examples should all pass
Refer to application routes in the controller under test
Given
a file named "spec/controllers/application_controller_spec.rb" with:
require "rails_helper"

Rails.application.routes.draw do
  match "/login" => "sessions#new", :as => "login", :via => "get"
end

RSpec.describe ApplicationController do
  controller do
    def index
      redirect_to login_url
    end
  end

  it "redirects to the login page" do
    get :index
    expect(response).to redirect_to("/login")
  end
end
When
I run rspec spec
Then
the examples should all pass

Last published about 1 month ago by myronmarston.