0

Prereq:

  • Rails 7.0.4
  • Devise 4.9.0 with hotwire/turbo support
  • Responders 3.1.0

Devise has the default config with

  config.responder.error_status = :unprocessable_entity
  config.responder.redirect_status = :see_other

lines in it.

It works properly with standard devise/registrations/new view and processing.

But when I try to add captcha check according to examples, it fails (see below).

class ApplicationController < ActionController::Base

  before_action :configure_permitted_parameters, if: :devise_controller?

  # Check captcha on :create only
  prepend_before_action :check_captcha_on_sign_up, if: Proc.new { request.controller_class == Devise::RegistrationsController }, only: [:create]

  protected

  def check_captcha_on_sign_up
    if CaptchaJob.new.valid?(params[:"smart-token"], request.remote_ip)
      flash.delete :alert
    else
      build_resource(sign_up_params)
      resource.valid?
      clean_up_passwords(resource)
      flash.alert = "Please, confirm you're not a robot"
      respond_with_navigational(resource) do
        render :new
      end
    end
  end

end

If I submit sign up form with captcha checked, everything is ok.

But if I submit form without captcha checked, I get this error:

undefined method `users_url' for #<Devise::RegistrationsController:0x00000000036600>

...

      clean_up_passwords(resource)
      flash.alert = "Please, confirm you're not a robot"
>>>>> respond_with_navigational(resource) do
        render :new
      end
    end

Exception causes section contains the message:

ActionView::MissingTemplate: Missing template devise/registrations/new, devise/new, application/new with {:locale=>[:ru], :formats=>[:turbo_stream], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]}. 

But the file devise/registrations/new.html.erb exists.

devise.rb without comments:

Devise.setup do |config|
  config.mailer_sender = '***'
  require 'devise/orm/active_record'
  config.case_insensitive_keys = [:email]
  config.strip_whitespace_keys = [:email]
  config.skip_session_storage = [:http_auth]
  config.stretches = Rails.env.test? ? 1 : 12
  config.reconfirmable = true
  config.expire_all_remember_me_on_sign_out = true
  config.password_length = 6..128
  config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
  config.reset_password_within = 6.hours
  config.sign_out_via = :delete
  config.responder.error_status = :unprocessable_entity
  config.responder.redirect_status = :see_other
end

Of course I tried to add config.navigational_formats = ['*/*', :html, :turbo_stream] to devise.rb, but it's for previous Devise version and it doesn't work anyway.

How to fix check_captcha_on_sign_up method to make it render new.html.erb view properly if captcha is not valid?

Thanks.

UPD: I created a fresh project with fail demo: https://github.com/noff/devise_rails7_captcha_fail_demo

noff
  • 115
  • 1
  • 5

1 Answers1

0

In your code you ask from your ApplicationController to render :new, as it said in 2.1 - Rendering an Action's View Layouts and Rendering in Rails , it automatically render the view associated with the controller. Your code take place in the ApplicationController and I think it try to re-render new view from ApplicationController.

So you need to send your user to the view generate by the devise controller, it should be: new_user_registration.

  def check_captcha_on_sign_up
    if CaptchaJob.new.valid?(params[:"smart-token"], request.remote_ip)
      flash.delete :alert
    else
      build_resource(sign_up_params)
      resource.valid?
      clean_up_passwords(resource)
      flash.alert = "Please, confirm you're not a robot"
      respond_with_navigational(resource) do
        redirect_to new_user_registration
      end
    end
  end

You should also check that stackoverflow response How to integrate recaptcha with devise? where the configuration of the registration take place in a RegistrationController that inherit from Devise::RegistrationsController.

LsQnlt
  • 19
  • 4
  • Hi. Thanks for your response. Unfortunately, it doesn't work: I tried to `render :new and return`. It fails with that error. I tried to `respond_with resource` (I took it from devise controller). Same result: error. I tried `redirect_to` -- it doesn't fail, but it loses form data (email, first_name, last_name) and use must fill it again. I tried according to the link [you mentioned](https://github.com/heartcombo/devise/wiki/How-To:-Use-Recaptcha-with-Devise). I literally copy/pasted it from the documentation. And it fails with the same error. – noff Mar 01 '23 at 16:03
  • Did you change the controller where you check the captcha ? Your first error is to check this captcha in ApplicationController. The method that check captcha must be in a Devise::RegistrationController. For generate such controller you can use this command `rails g devise:controllers users -c=registrations`. – LsQnlt Mar 01 '23 at 21:35
  • Sure. I generated new controller and put everything in it. Just copied everything from this article: https://github.com/heartcombo/devise/wiki/How-To:-Use-Recaptcha-with-Devise – noff Mar 02 '23 at 10:47
  • Is it always the same `MissingTemplate` error ? If so, did you checkout this stackoverflow thread (https://stackoverflow.com/questions/7374903/missing-template-with-devise-custom-registration-controller) that moving the registration template from `/views/devise/registrations` to `/views/registrations` ? – LsQnlt Mar 02 '23 at 12:35
  • Yes, I created a copy of view for the created controller. Sometimes it says the problem with html view, sometimes it says about turbo_stream view. I can't understand why and under what conditions. – noff Mar 02 '23 at 14:49
  • I created a repo with the fresh project to demonstrate the problem: https://github.com/noff/devise_rails7_captcha_fail_demo – noff Mar 04 '23 at 10:23