devise icon indicating copy to clipboard operation
devise copied to clipboard

Devise 4.8.1 + Rails 7.0.0 | Undefined method 'user_url'

Open ghost opened this issue 2 years ago • 16 comments

Pre-check

  • Created a new rails-app with rails new app-name -a propshaft -j importmap -c tailwind
  • Added gem 'devise', '~> 4.8', '>= 4.8.1' to Gemfile and followed installation instructions

Environment

  • Ruby 3.0.3p157
  • Rails 7.0.0
  • Devise 4.8.1

Current behavior

  • Receiving NoMethodError (undefined method 'user_url' for #<Devise::RegistrationsController:0x0000000000d638>) upon successful user registration.
  • User gets persisted in database

Demo app to reproduce the error is available here

Expected behavior

  • Redirect to root_path without error

ghost avatar Dec 18 '21 20:12 ghost

Ran into this at the same time as you 😆

Quick fix, tl;dr

Add :turbo_stream as a navigational format. This line goes in config/initializers/devise.rb. I haven't tested this extensively, but I think it should be fine.

config.navigational_formats = ['*/*', :html, :turbo_stream]

More detail

A few lines from a trace starting with the offending line in registrations controller: https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/app/controllers/devise/registrations_controller.rb#L25

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/app/controllers/devise/registrations_controller.rb#L111-L113

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/lib/devise/controllers/helpers.rb#L264-L266

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/lib/devise.rb#L218-L220

Basically, requests in Rails 7 may come with format :turbo_stream rather than simply :html. This causes is_navigational_format? to be falsey and thus after_sign_up_path_for returns nil. With location: nil for responds_with, the redirect path resolves from the resource - in our case the user.

I'm happy to open a PR for this, though someone with more familiarity with turbo should sanity check it.

nickrivadeneira avatar Dec 18 '21 22:12 nickrivadeneira

@erik-brueggemann my understanding is that method: :delete won't work with a link_to when not using UJS (which is not a dependency by default in Rails 7). So the sign_out method is going to be called as a GET, which is the fallback, resulting in an error.

You can try changing link_to to button_to (which I don't like), or add data-turbo-method="delete", like so:

<%= link_to "Log out", destroy_user_session_path,
data: {
 "turbo-method": :delete
}, class: "link-secondary smooth" %>

A problem I am trying to find a solution for with this approach is that upon singing out it won't redirect to the root, but to the page the user was on before signing out, which, of course, most probably requires authorisation, so it is not the best experience.

The approach above works without the @nickrivadeneira fix (however, you might be experiencing a different issue). I'm not sure what is it changes exactly in the behaviour. I was hoping it will be a fix for my issue, but it isn't... any help will be appreciated.

nortonandreev avatar Dec 20 '21 13:12 nortonandreev

Hi @nortonandreev, the problem you're describing is yet another one that resulted from the Rails 7 / turbo-rails aftermath as far as I can tell.

This particular issue here wasn't meant to address the log out mechanism, but rather user registration only. For that, the fix suggested by @nickrivadeneira makes sense to me - nevertheless you've got a point! It's probably a good idea to open a separate issue to find a permanent solution for that?

But since we've already brought it up, instead of changing from link_to to button_to and instead of adding the :delete data-tag, you might try editing your config/devise.rb to sign out via GET instead of DELETE

  # The default HTTP method used to sign out a resource. Default is :delete.
  config.sign_out_via = :get # <= change this from :delete to :get and remove the `method:` in your `link_to` helper

Happy to open up another issue if ya'll think it's two separate topics.

ghost avatar Dec 20 '21 19:12 ghost

But since we've already brought it up, instead of changing from link_to to button_to and instead of adding the :delete data-tag, you might try editing your config/devise.rb to sign out via GET instead of DELETE

just curious - wouldn't that open one up to csrf attacks?

modosc avatar Dec 21 '21 19:12 modosc

Hi @nortonandreev, the problem you're describing is yet another one that resulted from the Rails 7 / turbo-rails aftermath as far as I can tell.

This particular issue here wasn't meant to address the log out mechanism, but rather user registration only. For that, the fix suggested by @nickrivadeneira makes sense to me - nevertheless you've got a point! It's probably a good idea to open a separate issue to find a permanent solution for that?

But since we've already brought it up, instead of changing from link_to to button_to and instead of adding the :delete data-tag, you might try editing your config/devise.rb to sign out via GET instead of DELETE

  # The default HTTP method used to sign out a resource. Default is :delete.
  config.sign_out_via = :get # <= change this from :delete to :get and remove the `method:` in your `link_to` helper

Happy to open up another issue if ya'll think it's two separate topics.

The changelog says that "Please note that Turbo integration is not fully supported by Devise yet.". It would be nice if someone familiar with the matter updates us on what does this mean exactly and if there is some ETA of when full support will be added. I don't really want to waste hours implementing hacky solutions which might make my app vulnerable. On the other hand, I don't want to be waiting forever, if devise won't be fully updated to support Rails 7.

nortonandreev avatar Dec 24 '21 21:12 nortonandreev

method: :delete in my link_to dont working, only work this format > <%= link_to "Deletar", admin_admin_path(admin), data: { "turbo-method": :delete, confirm: "Certeza que deseja excluir essa conta?" }, class: "btn btn-danger btn-sm" %>

edusurf10 avatar Jan 25 '22 11:01 edusurf10

For now you have to disable turbo on devise links, i.e. data: { turbo: false }. I should have some time to look into more official turbo integration soon.

carlosantoniodasilva avatar Jan 25 '22 12:01 carlosantoniodasilva

For now you have to disable turbo on devise links, i.e. data: { turbo: false }. I should have some time to look into more official turbo integration soon.

all right, thanks.

edusurf10 avatar Jan 25 '22 15:01 edusurf10

As noted by @nortonandreev this worked for me in an app with Rails 7 and importmap

<%= link_to "Log out", destroy_user_session_path,
data: {
 "turbo-method": :delete
} %>

ahowardm avatar Jan 28 '22 16:01 ahowardm

https://github.com/heartcombo/devise/issues/5439#issuecomment-997292547

This solved my issue to help me close out the initial setup of my new application that I'm working on, thank you!

joshuaneedham avatar Feb 05 '22 22:02 joshuaneedham

The suggestion by @nortonandreev works for me, but adds an additional, failing and unnecessary (DELETE) HTTP request:

Started DELETE "/users/sign_out" for 127.0.0.1 at 2022-03-03 17:33:09 +0100
Processing by Users::SessionsController#destroy as TURBO_STREAM
  [...]
Redirected to http://localhost:3000/
Completed 302 Found in 5ms (ActiveRecord: 0.3ms | Allocations: 3175)


Started DELETE "/" for 127.0.0.1 at 2022-03-03 17:33:10 +0100
  
ActionController::RoutingError (No route matches [DELETE] "/")

john-999 avatar Mar 03 '22 16:03 john-999

I added , data: { turbo: false } to all link_to and form_for helpers on the Devise views.

5minpause avatar Apr 09 '22 14:04 5minpause

I am on Rails 7.0.2.3 and I didn't have this issue. Maybe upgrading to this version of rails or higher might fix it,

omokehinde avatar Apr 27 '22 23:04 omokehinde

im having this same problem in a app with bootstrap, link_to perfoms GET method instead DELETE even if i use data: {turbo_method: :delete} using button_to i manage to delete things, but confirmations dont work. Im guessing is something with bootstrap cuz in other project without it, destroy works just fine in link and button_to ..

b-sep avatar May 01 '22 16:05 b-sep

I am on Rails 7.0.2.3 and I didn't have this issue. Maybe upgrading to this version of rails or higher might fix it,

@omokehinde dont work im using the rails 7.0.2.3 and i have the same issue but when i register a user

pargara avatar May 17 '22 13:05 pargara

It works for me <%= button_to 'Logout', destroy_user_session_path, method: :delete, form: {turbolink: false} %>

sergiy-koshoviy avatar Jul 05 '22 22:07 sergiy-koshoviy

Hi everyone, This message is from Dec, 2022, I am currently making a rails app in which I do use devise, but certainly all of it works fine from registering a new user session to destroying the same. I am just a beginner at Ruby on Rails but this app needed nothing more.

This is what I did

<%= link_to "Log in", new_user_session_path %>

<%= link_to "Sign Up", new_user_registration_path %>

<%= link_to "Sign Out", destroy_user_session_path, 'data-turbo-method': :delete %>

I am attaching the repository You can check the application code to verify and let's close the issue finally.

HelloOjasMutreja avatar Dec 15 '22 01:12 HelloOjasMutreja

Ran into this at the same time as you laughing

Quick fix, tl;dr

Add :turbo_stream as a navigational format. This line goes in config/initializers/devise.rb. I haven't tested this extensively, but I think it should be fine.

config.navigational_formats = ['*/*', :html, :turbo_stream]

More detail

A few lines from a trace starting with the offending line in registrations controller:

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/app/controllers/devise/registrations_controller.rb#L25

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/app/controllers/devise/registrations_controller.rb#L111-L113

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/lib/devise/controllers/helpers.rb#L264-L266

https://github.com/heartcombo/devise/blob/025b1c873491908b346e4d394f54481ec18fb02c/lib/devise.rb#L218-L220

Basically, requests in Rails 7 may come with format :turbo_stream rather than simply :html. This causes is_navigational_format? to be falsey and thus after_sign_up_path_for returns nil. With location: nil for responds_with, the redirect path resolves from the resource - in our case the user.

I'm happy to open a PR for this, though someone with more familiarity with turbo should sanity check it.

This solution worked for me too!

iambenkis avatar Jan 03 '23 08:01 iambenkis

My sample app is working fine with the changes I described here: How to customize Devise for Rails 7.0 and Turbo - DEV Community

I tested these behaviors:

  • Sign up
  • Sign in and sign out
  • Edit account
  • Reset password
  • Cancel account

JunichiIto avatar Jan 04 '23 13:01 JunichiIto

Wanted to confirm that the article that @JunichiIto posted/wrote worked successfully for me. Thank you!

johnpitchko avatar Feb 03 '23 12:02 johnpitchko

The main branch should contain all that's necessary for fully working with Turbo now, which should fix this. A new version will be released soon, but feel free to test it out from the main branch in the meantime, and report back on any issues. Thanks.

carlosantoniodasilva avatar Feb 09 '23 21:02 carlosantoniodasilva

I have same issue after installing gem 'devise-security', '~> 0.17.0' Not sure what causes it, but after I removed that gem everything works fine. I had problem in new form (simple form gem, devise registrations controller).

alex223125 avatar Feb 24 '23 01:02 alex223125

@alex223125 I don't know much about that gem to help, sorry. They may need some tweak to work with Rails 7 and / or this latest Devise version.

carlosantoniodasilva avatar Feb 24 '23 12:02 carlosantoniodasilva

What about the case where the object is not persisted? I'm getting the same error on this line

https://github.com/heartcombo/devise/blob/main/app/controllers/devise/registrations_controller.rb#L34

      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource

botsarenthuman avatar Apr 04 '23 23:04 botsarenthuman

@botsarenthuman my first wild guess is that you're hitting something like this: https://github.com/heartcombo/devise/issues/5565#issuecomment-1457213530, where the object does not contain any errors associated with it (even if it's not persisted), so responders will try to redirect (it uses the presence of errors to determine how to respond), causing the error.

carlosantoniodasilva avatar Apr 04 '23 23:04 carlosantoniodasilva