theKindOfMe

September 25, 2010

reCAPTCHA with Rails 3 without plugins

Filed under: Uncategorized — yasi8h @ 8:14 am

I needed to get some sort of a captcha solution up and running with the rails project that i am working on. Looked around and sure enough there is a easy solution. reCAPTCHA! its popular and its seems solid. there were some plugins for rails that would making integrating it a breeze too!. But oh well usually things aren’t that easy for me :P. Turns out all of the plugins that i came across don’t directly support rails 3. They are not either updated or maintained. See this is the problem with plugins. You got a ton of them for rails but rails updates so fast that most of the plugins are not up-to-date. Specially if its not one of the super star plugins. Anyways having plugins is good. Having ones that are not updated is much better than having none.

I could have got one of the available plugins and hacked it to work with rails. But me being lazy and all that. I figured i would just implement things my self, like reinventing the wheel ;) Its pretty simple though. Heres how i did it.

BTW look here for a list of available plugins.

1. First of all head to http://www.google.com/recaptcha and get your self registered. It should be straight forward. Obtain and remember your private and public keys.

2. Although i am not using a plugin i don’t want go against DRY completely. So add this piece of reusable code to your ApplicationController. In this set the RECAPTCHA_PRIVATE_KEY to your private key.



class ApplicationController < ActionController::Base
  protect_from_forgery

  protected
  RECAPTCHA_PRIVATE_KEY = 'PRIVATE_KEY';

  #try and verify the captcha response. Then give out a message to flash
  def verify_recaptcha(remote_ip, params)

      responce = Net::HTTP.post_form(URI.parse('http://www.google.com/recaptcha/api/verify'),
                                    {'privatekey'=>RECAPTCHA_PRIVATE_KEY, 'remoteip'=>remote_ip, 'challenge'=>params[:recaptcha_challenge_field], 'response'=> params[:recaptcha_response_field]})
      result = {:status => responce.body.split("\n")[0], :error_code => responce.body.split("\n")[1]}

      if result[:error_code] == "incorrect-captcha-sol"
        flash[:alert] = "The CAPTCHA solution was incorrect. Please re-try"
      elsif
        flash[:alert] = "There has been a unexpected error with the application. Please contact the administrator. error code: #{result[:error_code]}"
      end

      result
  end
end

3. Add a new partial to views/share and name it as _recaptcha.erb (or as whatever template type you use). This will contain the stuff that goes in to a view where you wants to actually put the captcha in. For ex if you wants to use captcha where users are posting comments. You would render this partial in that view. Put the following code in to it. in this user your public key in place of PUBLIC_KEY.

<%= javascript_include_tag "http://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY" %>

<noscript>
	<iframe src="http://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY" height="300" width="500" frameborder="0"></iframe>
	<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
	<input type="hidden" name="recaptcha_response_field" value="manual_challenge">
</noscript>
<div id="captcha">
	<%= render '/share/recaptcha' %>
</div>

4. In the controller action that handles the post request for the comment creation (continuing the above example) you can use the following helper method to see if the user was able to solve the captcha accurately or not. If not you can get a error message and display that to the user or do something else.

# POST /comments
  # POST /comments.xml
  def create
    @comment = Comment.new(params[:comment])

    if verify_recaptcha(request.remote_ip, params)[:status] == 'false'
      @notice = "captcha incorrect"
      respond_to do |format|
        format.html { render :action => "new" }
        format.xml  { render :xml => @comment.errors, :status => :unprocessable_entity }
      end
    elsif
      respond_to do |format|
        if @comment.save
          format.html { redirect_to(@comment, :notice => 'Comment was successfully created.') }
          format.xml  { render :xml => @comment, :status => :created, :location => @comment }
        else
          format.html { render :action => "new" }
          format.xml  { render :xml => @comment.errors, :status => :unprocessable_entity }
        end
      end
    end
  end
5.  Thats it!. I did a example project while writing this post. You can get it from http://github.com/thekindofme/recaptcha-rails3-noplugin-example
Hope this helps.
About these ads

3 Comments »

  1. Thank you for this example, it works just fine!

    Comment by tehif — October 22, 2010 @ 3:34 pm

  2. thanks for the example !! That’s what I need.

    Comment by art — February 6, 2011 @ 10:20 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: