Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

No route matches Anonymous controller problem #636

Closed
g3d opened this Issue · 8 comments

6 participants

@g3d

As i see, anonymous controller doesn`t work. I expect test custom 404 error handling, but have only errors:

rspec spec/controllers/errors_controller_spec.rb

No DRb server is running. Running in local process instead ...
WARNING: Nokogiri was built against LibXML version 2.7.8, but has dynamically loaded 2.8.0
.FFFF

Failures:

  1) ApplicationController error raising should handle ActionController::RoutingError correctly
     Failure/Error: get :routing_error
     ActionController::RoutingError:
       No route matches {:controller=>"anonymous", :action=>"routing_error"}
     # ./spec/controllers/errors_controller_spec.rb:42:in `block (3 levels) in <top (required)>'

  2) ApplicationController error raising should handle ActionController::UnknownController correctly
     Failure/Error: get :my_membership
     ActionController::RoutingError:
       No route matches {:controller=>"anonymous", :action=>"my_membership"}
     # ./spec/controllers/errors_controller_spec.rb:46:in `block (3 levels) in <top (required)>'

  3) ApplicationController error raising should handle ActionController::RoutingError correctly
     Failure/Error: get :action_not_found
     ActionController::RoutingError:
       No route matches {:controller=>"anonymous", :action=>"action_not_found"}
     # ./spec/controllers/errors_controller_spec.rb:50:in `block (3 levels) in <top (required)>'

  4) ApplicationController error raising should handle ActionController::RoutingError correctly
     Failure/Error: get :record_not_found
     ActionController::RoutingError:
       No route matches {:controller=>"anonymous", :action=>"record_not_found"}
     # ./spec/controllers/errors_controller_spec.rb:54:in `block (3 levels) in <top (required)>'

Finished in 2.21 seconds
5 examples, 4 failures

Failed examples:

rspec ./spec/controllers/errors_controller_spec.rb:41 # ApplicationController error raising should handle ActionController::RoutingError correctly
rspec ./spec/controllers/errors_controller_spec.rb:45 # ApplicationController error raising should handle ActionController::UnknownController correctly
rspec ./spec/controllers/errors_controller_spec.rb:49 # ApplicationController error raising should handle ActionController::RoutingError correctly
rspec ./spec/controllers/errors_controller_spec.rb:53 # ApplicationController error raising should handle ActionController::RoutingError correctly

cat spec/controllers/errors_controller_spec.rb

require 'spec_helper'
describe ErrorsController do
  describe "GET 'error_404'" do
    it "returns http success" do
      get 'error_404'
      response.status.should be(404)
    end
  end
end

describe ApplicationController, type: :controller do
  controller do
    def routing_error
      raise ActionController::RoutingError.new("not_found")
    end

    def unknown_controller
      raise ActionController::UnknownController.new("not_found")
    end

    def method
      raise AbstractController::ActionNotFound.new("not_found")
    end

    def record_not_found
      raise ActiveRecord::RecordNotFound.new("not_found")
    end
  end

  describe "error raising" do
    it "should handle ActionController::RoutingError correctly" do
      get :routing_error
      response.status.should be(404)
    end
    it "should handle ActionController::UnknownController correctly" do
      get :my_membership
      response.status.should be(404)
    end
    it "should handle ActionController::RoutingError correctly" do
      get :action_not_found
      response.status.should be(404)
    end
    it "should handle ActionController::RoutingError correctly" do
      get :record_not_found
      response.status.should be(404)
    end
  end
end

cat app/controllers/application_controller.rb

class ApplicationController < ActionController::Base

  layout 'public'

  protect_from_forgery
  before_filter :check_auto_login
  around_filter :rescue_access_denied

  def check_auto_login
    mid = params.delete(:mid)
    expires_in = params.delete(:expires_in)
    checksum = params.delete(:checksum)
    if mid.present? || expires_in.present? || checksum.present?
      begin
        if not_expired?(expires_in) && checksum_matches?(checksum, request.env['QUERY_STRING'])
          member = Member.find_by_id(mid)
          sign_in :member, member
        end
      rescue Exception => e
        Rails.logger.warn("Auto login failed #{e.message}, #{e.backtrace[0..5].join("\n")}")
      end
      redirect_to url_for(params)
    end
  end

  def rescue_access_denied
    begin
      yield
    rescue CanCan::AccessDenied
      redirect_to unauthorized_path and return
    end
  end

  def get_chrome_frame
    render layout: false
  end

  def unauthorized
    render text: "unauthorized", status: 401
  end

  unless Rails.application.config.consider_all_requests_local
    exceptions_404 = [
      ActionController::RoutingError,
      ActionController::UnknownController,
      AbstractController::ActionNotFound,
      ActiveRecord::RecordNotFound ]
    rescue_from *exceptions_404, with: lambda { |exception| render_error 404, exception }
  end

  protected

  def render_error(status, exception)
    respond_to do |format|
      format.html { render template: "errors/error_#{status}", layout: 'public', status: status }
      format.all { render nothing: true, status: status }
    end
  end

  def get_referring_member
    Member.find_by_guid(cookies[:referred_by])
  end

  def get_referring_member_name
    if (referring_member = get_referring_member)
      referring_member.name
    else
      ""
    end

  end

  private

  def not_expired?(expires_in)
    Time.current.to_i < Integer(expires_in) if expires_in.present?
  end


  def after_sign_in_path_for(resource)
    case resource
    when Member
      if params[:member] && params[:member][:redirect].present?
        params[:member][:redirect]
      elsif current_member.engaged_member?
        member_dashboard_path
      else
        prospect_dashboard_path
      end
    when User
      if can? :access, :admin
        params[:user].try(:[], :redirect) || admin_dashboard_path
      else
        root_path
      end
    else
      super
    end
  end
end

I already looked to similar cases (like #573 or http://stackoverflow.com/questions/7027518/no-route-matches-rspecs-anonymous-controller) but it doesn`t helped me, so i writed this issue.

rails (3.2.1)
rspec (2.11.0, 2.10.0)
rspec-core (2.11.1, 2.10.1)
rspec-expectations (2.11.3, 2.10.0)
rspec-mocks (2.11.3, 2.10.1)
rspec-rails (2.11.4, 2.10.1)

@andrewhavens

I am running into a similar issue. Not sure how to test this type of scenario.

@alindeman
Collaborator

Thanks for the detailed report. I'll see if I can figure out what's going on here soon; in the mean time, you might be able to test the coverage you want by testing this at a higher level using request specs.

@pcasaretto

I think this is expected, see this:
c8523df
However, I believe this assumption is very limiting.
Maybe we can force the routing somehow?

@sickill

I have similar issue and wondering what's the best way to handle this.

@vanstee

Anonymus controllers only create resource routes. So routes like routing_error wont exist but stuff like index or show should work. Here's the spec that defines this functionality:

https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/anonymous-controller#anonymous-controllers-only-create-resource-routes

Does this resolve the issue you were seeing?

@alindeman
Collaborator

It is possible to do something like this:

require "spec_helper"

describe ApplicationController do
  controller do
    def custom
      render :text => "custom!"
    end
  end

  describe "#custom" do
    before do
      routes.draw { get "custom" => "anonymous#custom" }
    end

    it "responds to GET" do
      get :custom
      expect(response.body).to eq "custom!"
    end
  end
end

YMMV as to whether it's a good idea for your app :) And @vanstee is correct in that we only draw the default resources routes for you.

@alindeman alindeman closed this
@pcasaretto

Very nice! Thanks @alindeman . That should be on the docs.
Quick question, will the drawn routes get rolled back, or do we have to do it on our own?

@alindeman
Collaborator

The routes are rolled back automatically. If you'd like to submit a documentation update, I'd likely pull it in :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.