No route matches Anonymous controller problem #636

Closed
g3d opened this Issue Nov 13, 2012 · 8 comments

Comments

Projects
None yet
6 participants

g3d commented Nov 13, 2012

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)

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

Contributor

alindeman commented Nov 22, 2012

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.

Contributor

pcasaretto commented Nov 27, 2012

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

Contributor

sickill commented Dec 1, 2012

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

Contributor

vanstee commented Dec 6, 2012

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?

Contributor

alindeman commented Dec 6, 2012

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 Dec 6, 2012

Contributor

pcasaretto commented Dec 6, 2012

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?

Contributor

alindeman commented Dec 6, 2012

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