Skip to content

How To: Use Recaptcha with Devise

ianli edited this page Dec 13, 2011 · 25 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/Recaptcha
  2. Install the Recaptcha gem found here (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) the line before your submit button.
  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. Remember that "devise" expects you to use flash[:notice] and flash[:alert] and not flash[:error]. 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
          clean_up_passwords(resource)
          flash.now[:alert] = "There was an error with the recaptcha code below. Please re-enter the code."
          render_with_scope :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.

With OmniAuth:

  class RegistrationsController < Devise::RegistrationsController
  
    def create
      if session[:omniauth] == nil #OmniAuth
        if verify_recaptcha
          super
          session[:omniauth] = nil unless @user.new_record? #OmniAuth
        else
          build_resource
          clean_up_passwords(resource)
          flash[:alert] = "There was an error with the recaptcha code below. Please re-enter the code."
          render_with_scope :new
        end
      else
        super
        session[:omniauth] = nil unless @user.new_record? #OmniAuth
      end
    end

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.

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
      resource.valid?
      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".

Clone this wiki locally