Feature: anonymous controller

  Use the `controller` method to define an anonymous controller derived from
  `ApplicationController`. 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 configure RSpec to use the described class:

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

      describe BaseController do
        controller { ... }
        # ^^ creates an anonymous subclass of `BaseController`

  Scenario: specify error handling in ApplicationController
    Given a file named "spec/controllers/application_controller_spec.rb" with:
      """ruby
      require "spec_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

      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

  Scenario: specify error handling in subclass of ApplicationController
    Given a file named "spec/controllers/application_controller_subclass_spec.rb" with:
      """ruby
      require "spec_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

      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

  Scenario: infer base class from the described class
    Given a file named "spec/controllers/base_class_can_be_inferred_spec.rb" with:
      """ruby
      require "spec_helper"

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

      class ApplicationController < ActionController::Base; end

      class ApplicationControllerSubclass < ApplicationController; end

      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

  Scenario: invoke around filter in base class
    Given a file named "spec/controllers/application_controller_around_filter_spec.rb" with:
      """ruby
      require "spec_helper"

      class ApplicationController < ActionController::Base
        around_filter :an_around_filter

        def an_around_filter
          @callback_invoked = true
          yield
        end
      end

      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_true
        end
      end
      """
    When I run `rspec spec`
    Then the examples should all pass

  Scenario: anonymous controllers only create resource routes
    Given a file named "spec/controllers/application_controller_spec.rb" with:
    """ruby
    require "spec_helper"

    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

  Scenario: draw custom routes for anonymous controllers
    Given a file named "spec/controllers/application_controller_spec.rb" with:
    """ruby
    require "spec_helper"

    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

  Scenario: refer to application routes in the controller under test
    Given a file named "spec/controllers/application_controller_spec.rb" with:
    """ruby
    require "spec_helper"

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

    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
