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

Rails 8: route initialization messed up #5716

Open
miharekar opened this issue Sep 27, 2024 · 3 comments
Open

Rails 8: route initialization messed up #5716

miharekar opened this issue Sep 27, 2024 · 3 comments

Comments

@miharekar
Copy link

miharekar commented Sep 27, 2024

Environment

  • Ruby 3.3.5
  • Rails Rails 8.0.0.beta1
  • Devise 4.9.4

Current behavior

A bit of story/context to help with discoverability of this issue if anyone is googling with similar symptoms.

When I upgraded my app to Rails 8 beta ActionCable stopped working with a peculiar message in web console:

connection.js:39 WebSocket connection to 'wss://visualizer.coffee/cable' failed

And indeed I saw a lot of ActionController::RoutingError (No route matches [GET] "/cable") in the logs.

At first I thought it's an issue with my hosting provider Fly, but then I was able to replicate this locally. Not in development environment though, but with RAILS_ENV=production PORT=3001 rails s I got those same errors.

I assumed something in Rails broke (it is beta after all) so I made a quick rails new app, and, damn it, it worked just fine in production env.

A couple of bundle opens later and pokings around I found this block which prepends the mounting of "/cable" or whatever the ActionCable mount_path is set to. With some further puts debugging I found that in the brand new app the block registers and executes while in my app it registers but never executes.

I added some puts debugs inside ActionDispatch#clear! and found that in the new app the ActionCable initializer is registered before first clear call, but in my app it happened after. So it has no chance to run the block. Culprit found.

Now I needed to know why this happens and I put some puts caller in there. The only diff was that one included devise-4.9.4/lib/devise/rails.rb:17 which is this piece of code with comment # Force routes to be loaded if we are doing any eager load.

I lack the deep knowledge of Devise to know how to proceed or what to do now, but here's how you can replicate it:

  1. rails new name_of_app with Rails version 8.0.0.beta1
  2. add devise to Gemfile and bundle
  3. run Rails in production with RAILS_ENV=production PORT=3001 rails s
  4. curl localhost:3001/cable

Without devise you get Page not found% response with these logs:

[0812aa3e-bfcd-41a5-958c-c27ab4b2a982] Started GET "/cable" for 127.0.0.1 at 2024-09-27 13:45:09 +0200
[0812aa3e-bfcd-41a5-958c-c27ab4b2a982] Started GET "/cable"[non-WebSocket] for 127.0.0.1 at 2024-09-27 13:45:09 +0200
[0812aa3e-bfcd-41a5-958c-c27ab4b2a982] Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: , HTTP_UPGRADE: )
[0812aa3e-bfcd-41a5-958c-c27ab4b2a982] Finished "/cable"[non-WebSocket] for 127.0.0.1 at 2024-09-27 13:45:09 +0200

as expected.

With devise you get 404 page with these logs:

[6795276c-a698-4bf8-bf9f-d4394a41e648] Started GET "/cable" for 127.0.0.1 at 2024-09-27 13:44:46 +0200
[6795276c-a698-4bf8-bf9f-d4394a41e648]
[6795276c-a698-4bf8-bf9f-d4394a41e648] ActionController::RoutingError (No route matches [GET] "/cable"):
[6795276c-a698-4bf8-bf9f-d4394a41e648]

With devise and reload_routes set to false in the initializer it also works, but probably it should work out of the box? 😅

Let me know if something isn't clear and/or how I can help out.

miharekar added a commit to miharekar/visualizer that referenced this issue Sep 27, 2024
@excid3
Copy link
Contributor

excid3 commented Oct 4, 2024

Got bit by this one today. Thanks for this.

Can confirm, config.reload_routes = false in config/initializers/devise.rb fixed it for me.

@excid3
Copy link
Contributor

excid3 commented Oct 5, 2024

Doing some digging, I think this is a regression in Rails related to this refactoring in Rails 8, not so much a bug in Devise. rails/rails@cdb2835

@gmcgibbon would probably know best, but my hunch is that since the routes are already loaded due to this Devise flag, the after_initialize prepend saves the block to be used, but it should actually run it immediately since it's already loaded.

@nwarwick
Copy link

Wow you saved me @miharekar! Thank you.

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

No branches or pull requests

3 participants