heartcombo / devise

Flexible authentication solution for Rails with Warden.
http://blog.plataformatec.com.br/tag/devise/
MIT License
23.89k stars 5.54k forks source link

Rails7+Devise+Captcha: undefined method `users_url' && Missing template users/registrations/new #5565

Closed noff closed 1 year ago

noff commented 1 year ago

Environment

Current behavior

Here is a demo project to test: https://github.com/noff/devise_rails7_captcha_fail_demo

I try to inject captcha check on sign up for Rails7 with hotwire + Devise.

I used this manual as a start point: https://github.com/heartcombo/devise/wiki/How-To:-Use-Recaptcha-with-Devise

I generated users/registrations controller and users/registrations/new view.

Added custom create method to Users::RegistrationsController:

def create
    if params[:captcha].present?
      flash.discard :captcha
      super
    else
      self.resource = resource_class.new sign_up_params
      resource.validate
      set_minimum_password_length
      clean_up_passwords resource
      flash[:captcha] = "Click captcha"
      respond_with_navigational(resource) do
        render :new
      end
    end
  end

When I submit the form, I get this error:

undefined method `users_url' for #<Users::RegistrationsController:0x000000000230f0>

[ActionView::MissingTemplate: Missing template users/registrations/new, devise/registrations/new, devise/new, application/new with {:locale=>[:en], :formats=>[:turbo_stream], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]}. Searched in: * "/Users/mkechinov/Developer/devise_captcha_rails_7/app/views" * "/Users/mkechinov/.rvm/gems/ruby-2.7.5/gems/devise-4.9.0/app/views" * "/Users/mkechinov/.rvm/gems/ruby-2.7.5/gems/turbo-rails-1.4.0/app/views" * "/Users/mkechinov/.rvm/gems/ruby-2.7.5/gems/actiontext-7.0.4.2/app/views" * "/Users/mkechinov/.rvm/gems/ruby-2.7.5/gems/actionmailbox-7.0.4.2/app/views"](http://localhost:3000/users/sign_up#)

Expected behavior

If captcha validation is failed, the sign-up form should be displayed with model's validation messages instead of 500 error.

carlosantoniodasilva commented 1 year ago

Thanks for reporting with a sample app, that's always helpful.

The resource you're passing to respond_with_navigational has no errors (i.e. errors.empty? is true), so it will try to redirect, causing the undefined method 'users_url'.

You need to either add some error to the object, or get rid of respond_with_navigational altogether (you probably don't need it I imagine), and just re-render with something like render :new, status: :unprocessable_entity so that Turbo knows to re-render the body content in place correctly.

TL;DR: replace

      respond_with_navigational(resource) do
        render :new
      end

with

      render :new, status: :unprocessable_entity

and the error should go away.