You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails7+Devise+Captcha报错:undefined method `users_url',如何修复验证码校验逻辑?

问题背景

前置条件:

  • Rails 7.0.4
  • 支持Hotwire/Turbo的Devise 4.9.0
  • Responders 3.1.0

Devise配置包含以下设置:

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

标准Devise注册流程正常运行,但添加验证码校验后出现异常。在ApplicationController中添加的校验代码如下:

class ApplicationController < ActionController::Base

  before_action :configure_permitted_parameters, if: :devise_controller?

  # 仅在创建动作时校验验证码
  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 = "请确认您不是机器人"
      respond_with_navigational(resource) do
        render :new
      end
    end
  end

end

验证码校验通过时流程正常,但校验不通过时抛出错误:undefined method 'users_url' for #<Devise::RegistrationsController:0x00000000036600>。异常详情显示:

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]}. 

但devise/registrations/new.html.erb文件实际存在。完整Devise配置(无注释):

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

已尝试添加config.navigational_formats = ['*/*', :html, :turbo_stream]但无效,需修复check_captcha_on_sign_up方法,使校验不通过时能正确渲染new.html.erb视图。


修复方案

问题核心是Turbo提交表单时请求格式为turbo_stream,但现有视图仅支持html格式,且respond_with_navigational在Turbo环境下的处理逻辑不符合预期。修改check_captcha_on_sign_up方法如下:

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.now.alert = "请确认您不是机器人"
    # 明确指定渲染html格式的注册表单,并设置正确的错误状态码
    render "devise/registrations/new", formats: [:html], status: :unprocessable_entity
  end
end

关键调整点:

  1. 直接调用render并指定formats: [:html],避免Turbo寻找不存在的turbo_stream模板
  2. 使用flash.now替代flash,确保错误提示仅在当前请求内有效(渲染视图属于同一次请求,无需跨请求保留提示)
  3. 设置status: :unprocessable_entity,与Devise配置的错误状态码保持一致

修改后,验证码校验不通过时会正确渲染注册表单页面并显示错误提示,不再出现模板缺失或路由方法未定义的错误。

内容的提问来源于stack exchange,提问作者noff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 13:03:31