没有路由匹配rspec的匿名控制器

时间:2011-08-11 14:18:39

标签: ruby-on-rails-3 rspec

根据我对rspec spec的理解,我希望通过以下示例。

describe ApplicationController do

  controller do
    def test
    end
  end

  it "calls actions" do
    get :test
  end

end

相反,它失败了:

No route matches {:controller=>"anonymous", :action=>"test"}

我甚至尝试在路径文件中为“匿名”控制器定义路由,但无济于事。这里有什么我想念的吗?这应该有用,不应该吗?

6 个答案:

答案 0 :(得分:24)

要在匿名控制器规范中使用自定义路由,您需要修改前一个块中的路由集。 RSpec已在前一个块中使用resources :anonymous设置RESTful路由,并在后块中恢复原始路由。因此,要获得自己的路线,只需在@routes上调用draw并添加所需内容。

以下是测试ApplicationController

rescue_from CanCan::AccessDenied规范的示例
require 'spec_helper'

describe ApplicationController
  controller do
    def access_denied
      raise CanCan::AccessDenied
    end
  end

  before do
    @routes.draw do
      get '/anonymous/access_denied'
    end
  end

  it 'redirects to the root when access is denied' do
    get :access_denied
    response.should redirect_to root_path
  end

  it 'sets a flash alert when access is denied' do
    get :access_denied
    flash.alert.should =~ /not authorized/i
  end
end

<强>更新

在RSpec 2.12附近,对此的处理得到了改善。如果您使用&gt; 2.12然后你不再需要挂钩@routes

Draw custom routes for anonymous controllers

答案 1 :(得分:21)

我遇到了类似的问题。在我的例子中,解决方案是在测试中的get请求中包含:id参数。

get :test, :id => 1

检查您的路线并查看您是否缺少某个参数(可能是:id),然后将其添加到测试中。

答案 2 :(得分:3)

我遇到了同样的问题,我读了这个controller方法代码(定义为here):

def controller(base_class = nil, &body)
  base_class ||= RSpec.configuration.infer_base_class_for_anonymous_controllers? ?
                   controller_class :
                   ApplicationController

  metadata[:example_group][:described_class] = Class.new(base_class) do
    def self.name; "AnonymousController"; end
  end
  metadata[:example_group][:described_class].class_eval(&body)

  # ADD ROUTES IN BEFORE BLOCK
  before do
    @orig_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new
    @routes.draw { resources :anonymous } # <==== HERE ARE THE ROUTES
  end

  after do
    @routes, @orig_routes = @orig_routes, nil
  end
end

代码中的大写注释是我的,基本上你只能在使用这个方法时使用标准的restful路由。此外,您不能在routes.rb文件中使用自定义路由,因为它们会被覆盖整个示例并在之后恢复。

答案 3 :(得分:3)

似乎rspec为您提供了一组RESTful路由。因此,如果您只在匿名控制器中使用标准操作名称,则不会出现此问题。到目前为止,我从来没有理由使用除“索引”之外的任何东西。

describe ApplicationController do
  describe 'respond_with_foo' do
    controller do
      def index
        respond_with_foo
      end
    end

    it 'should respond with foo' do
      get :index
      response.should be_foo
    end
  end
end

答案 4 :(得分:1)

我遇到了同样的问题,并找到了一个适合我的解决方案。关键是在测试规范中映射出那些路线:

require 'spec_helper'

describe ApplicationController do
  #Base class should be inferred
  controller do
    def not_found
      raise ActiveRecord::RecordNotFound
    end
  end

  def with_error_routing
    with_routing do |map|
      map.draw do
        get '/not_found' => "anonymous#not_found",     :as => :not_found
      end
      yield
    end
  end

  describe "handling ActiveRecord::RecordNotFound" do
    it "renders the 404 template" do
      with_error_routing do
        get :not_found
        response.should render_template 'error/404'
      end
    end
  end
end

答案 5 :(得分:0)

我能够通过以下补丁来解决这个问题:

module RSpec::Rails
  module ControllerExampleGroup
    module ClassMethods
      def controller(base_class = nil, &body)
        base_class ||= RSpec.configuration.infer_base_class_for_anonymous_controllers? ?
            controller_class :
            ApplicationController

        metadata[:example_group][:described_class] = Class.new(base_class) do
          def self.name; "AnonymousController"; end
        end
        metadata[:example_group][:described_class].class_eval(&body)

        ######## PATCH START ########
        custom_routes = @custom_routes # Copy over routes to local variable so it will be accessible
        before do
          @orig_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new
          if custom_routes # if this was set then pass that to the draw function
            @routes.draw &custom_routes
          else
            @routes.draw { resources :anonymous } # else do what it used to do before
          end
          ######### PATCH END #########

          routes = @routes
          described_class.send(:define_method, :_routes) { routes }
        end

        after do
          @routes, @orig_routes = @orig_routes, nil
        end
      end

      ######## PATCH START ########
      def custom_routes &block
        @custom_routes = block
      end
      ######### PATCH END #########
  end
end

在spec_helper中需要该文件,然后在测试中只需执行:

    describe ApplicationController do
      describe 'respond_with_foo' do
        custom_routes do
          get :bar, controller: :anonymous, action: :bar
        end
        controller do
          def index
            respond_with_foo
          end
        end

        it 'should respond with foo' do
          get :index
          response.should be_foo
        end
      end
    end

如果有人问,我在infer_base_class_for_anonymous_controllers设置为false的情况下测试了这段代码。