Skip to content

How To: Use Recaptcha with Devise

Ben edited this page Feb 22, 2016 · 63 revisions

WARNING: The first draft of this page was done by a total n00b. There wasn't any help here for Recaptcha before, so he hopes this does help some people, but other more experienced should clean this up at a later date.

  1. Get your keys from Google's Recaptcha
  2. Install the Recaptcha gem (note: for Rails 3 do gem 'recaptcha', :require => 'recaptcha/rails')
  3. Add <%= recaptcha_tags %> on your New Registration view (you must have generated Devise views)
  4. Create/Update your RegistrationsController - see the "controllers" section in the README to understand how to set up your own Devise controllers, and don't forget to update the routes once you do. Include the following (the first is for a clean Devise install, and the second is for if you use OmniAuth like me):

Clean

    class RegistrationsController < Devise::RegistrationsController
      def create
        if verify_recaptcha
          super
        else
          build_resource(sign_up_params)
          clean_up_passwords(resource)
          flash.now[:alert] = "There was an error with the recaptcha code below. Please re-enter the code."      
          flash.delete :recaptcha_error
          render :new
        end
      end
    end
  1. In Rails 3.x you may need to add:
# ./config/application.rb
require 'net/http'

to support the Recaptcha gem.

Alternate implementation

Warning: I'm not sure I'm any more qualified on this than the OP, but I preferred this setup in my own app.

Advice from a reader: If the sign-up is by email as primary key, giving an error that the email is already taken (regardless of ReCaptcha result) means that it could be used for email harvesting.

The benefit to this method is that we can add any ReCaptcha errors to the rest of the form errors instead of an either/or scenario as would happen with the controllers listed above.

Steps 1 - 4 are the same

class Users::RegistrationsController < Devise::RegistrationsController
  def create
    if !verify_recaptcha
      flash.delete :recaptcha_error
      build_resource sign_up_params
      resource.errors.add :base, "There was an error with the recaptcha code below. Please re-enter the code."
      clean_up_passwords resource
      respond_with_navigational(resource) { render_with_scope :new }
    else
      flash.delete :recaptcha_error
      super
    end
  end
  
  def clean_up_passwords(*args)
    # Delete or comment out this method to prevent the password fields from 
    # repopulating after a failed registration
  end
end

The flash.delete :recaptcha_error gets rid of the default error from the ReCaptcha gem, which in my case kept appearing as "incorrect-captcha-sol".

For Devise 2.x change

respond_with_navigational(resource) { render_with_scope :new }

into

respond_with_navigational(resource) { render :new }

Notice! Captcha for Login

If you want to use captcha on your login page, you need to care about a security issue!

By default, Devise uses require_no_authentication method as before_filter for Session#new action.

That means Devise will auto check login and do login event before your Session#new action, so your verify_recaptcha check won't work.

So you need to skip this method like this:

class SessionsController < Devise::SessionsController
  skip_before_filter :require_no_authentication, :only => [:new]  

  def create
    if verify_recaptcha
      super
    else
      build_resource
      flash[:error] = "Captcha has wrong, try a again."
      respond_with_navigational(resource) { render :new }
    end    
  end
end

Or with prepend_before_action

class SessionsController < Devise::SessionsController

  prepend_before_action :recaptcha, only: [:create]

  def recaptcha    
    if not verify_recaptcha
      redirect_to "/users/sign_in"
    end    
  end

  def create
    # custom sign-in code
  end

end

More info about this: #2016

Captcha with Devise 2.x

If the above method doesn't work then try

  before_filter :check_user_validation, :only=>:create

  def check_user_validation
     #validate user or redirect with this method
  end

Recaptcha::RecaptchaError

This error getaddrinfo: nodename nor servname provided, or not known, can be due to a misconfigured initializer (recaptcha.rb) or rails not loading the net/http library. The Alternate implementation worked for me after I added it as below.

# config/application.rb

require 'net/http'

Clone this wiki locally