Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anonymous controller breaks ActionController::UrlGenerator on delete route #2045

Open
sebscholl opened this issue Dec 3, 2018 · 6 comments
Labels

Comments

@sebscholl
Copy link

What Ruby, Rails and RSpec versions are you using?

Ruby version: 2.5.1
Rails version: 5.2
Rspec version: 3.9.0

Observed behaviour

When adding an anonymous controller to a controller test suite, it breaks the delete route. Removing the anonymous controller leaves everything else working fine.

Expected behaviour

I expect:

delete :destroy

To not throw:

ActionController::UrlGenerationError:
       No route matches {:action=>"destroy", :controller=>"sessions"}

When an anonymous controller is present.

 # Test layout rendering
  controller do
    def test_index
      render 'anonymous/index'
    end
  end

Can you provide an example app?

  1. Running this test, the anonymous controller test passes.
  2. The delete session tests fail with the error ActionController::UrlGenerationError: No route matches {:action=>"destroy", :controller=>"sessions"}
require 'rails_helper'

RSpec.describe SessionsController, type: :controller do
  # Resources
  let(:manager) { create(:manager) }

  # Test layout rendering
  controller do
    def test_index
      render 'anonymous/index'
    end
  end

  describe 'defaults to unauthenticated layout' do
    before do
      routes.draw { get 'test_index' => 'sessions#test_index' }
      get :test_index
    end

    it 'renders the unauthenticated layout' do
      expect(subject).to render_template('layouts/unauthenticated/base')
    end
  end

  describe "DELETE #destroy" do
    before do
      login(manager)

      delete :destroy
    end

    it 'redirects to the login path' do
      expect(response).to redirect_to(login_path)
    end

    it "returns http 302" do
      expect(response).to have_http_status(302)
    end
  end
end

If the anonymous controller is removed, the delete paths run as expected.

require 'rails_helper'

RSpec.describe SessionsController, type: :controller do
  # Resources
  let(:manager) { create(:manager) }

  describe "DELETE #destroy" do
    before do
      login(manager)

      delete :destroy
    end

    it 'redirects to the login path' do
      expect(response).to redirect_to(login_path)
    end

    it "returns http 302" do
      expect(response).to have_http_status(302)
    end
  end
end
@JonRowe
Copy link
Member

JonRowe commented Dec 4, 2018

What does your routing look like for SessionsController? If you read the documentation for the currently released version (which is 3.8 not 3.9) you'll see that routes are only created for standard resource routes, so what I think what is happening here is you are missing the correct route for delete :destroy as the "standard resource route" expects an id. You can fix your spec by supplying an id or drawing the route manually as you have for your test_index.

@JonRowe JonRowe changed the title Anonymous controller breaks ActionController::UrlGenerator on delete rout Anonymous controller breaks ActionController::UrlGenerator on delete route Dec 4, 2018
@fables-tales
Copy link
Member

@JonRowe is this because we don't reset the routes after the routes.draw call?

@JonRowe
Copy link
Member

JonRowe commented Dec 19, 2018

@samphippen No I think it's because we use the default "multiple resources" REST routes e.g. DELETE /resource/:id and theres no ID.

@fables-tales
Copy link
Member

ahh gotcha. I think this is probably a valid bug then. I'll see if I can work up a fix.

@cjbottaro
Copy link

Having an anonymous controller breaks my routes also.

require 'rails_helper'

RSpec.describe Users::SessionsController, type: :controller do
  fixtures :users

  controller do
  end

  describe "GET #ask_email" do

    it "returns a success response" do
      get :ask_email, params: {}
      expect(response).to be_successful
    end

  end

end

Results in

  1) Users::SessionsController GET #ask_email returns a success response
     Failure/Error: get :ask_email, params: {}

     ActionController::UrlGenerationError:
       No route matches {:action=>"ask_email", :controller=>"users/sessions"}
     # /Users/cjbottaro/.gem/ruby/2.5.3/gems/devise-4.5.0/lib/devise/test/controller_helpers.rb:35:in `block in process'
     # /Users/cjbottaro/.gem/ruby/2.5.3/gems/devise-4.5.0/lib/devise/test/controller_helpers.rb:102:in `catch'
     # /Users/cjbottaro/.gem/ruby/2.5.3/gems/devise-4.5.0/lib/devise/test/controller_helpers.rb:102:in `_catch_warden'
     # /Users/cjbottaro/.gem/ruby/2.5.3/gems/devise-4.5.0/lib/devise/test/controller_helpers.rb:35:in `process'
     # ./spec/controllers/users/sessions_controller_spec.rb:14:in `block (3 levels) in <top (required)>'

Simply removing the controller block fixes it.

@JonRowe
Copy link
Member

JonRowe commented Jun 22, 2019

@cjbottaro in your case this is expected, controller creates a new controller which has the standard resource routes, thus as you haven't defined a route called ask_email for it you get the error, you need to draw the routes yourself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants