This article was peer reviewed by Thom Parkin. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!
ReCAPTCHA is a free service from Google that helps protect websites from spam and abuse. A “CAPTCHA” is a test to tell humans and robot apart. This kind of service is important for websites or web applications with lots of user generated content. The test is easy for a human to solve, but hard for bots and other malicious software to figure out.
In this tutorial, I will show you how to integrate ReCAPTCHA to your Rails application using ReCAPTCHA gem. You will also see how to add it to Devise.
Let’s get started!
ReCAPTCHA Setup
First, you need to obtain a ReCAPTCHA API Key. I presume that you have a Google account already, but if not, sign up for one.
On the ReCAPTCHA page, enter the details of your application and click Register. You will be presented with a page that contains your site key and secret key. Copy those to a safe location, it is wise to prevent these keys from being checked into source control.
Rails Application Setup
From your terminal generate a new rails application
rails new mypets
And bundle install
I chose Pets because I like dogs and I hope to get two soon 🙂
Let us generate a scaffold for our application:
class="language-bash"rails g scaffold Pet name:string pets_type:string
Then migrate your database:
class="language-bash"rake db:migrate
Integrating ReCAPTCHA
Add the following gems to your Gemfile
and bundle install
:
#Gemfile
gem 'dotenv-rails', :require => 'dotenv/rails-now'
gem "recaptcha", require: "recaptcha/rails"
Create a .env file in the root folder of your project and paste your ReCAPTCHA keys in there:
RECAPTCHA_PUBLIC_KEY = '<YOUR PUBLIC KEY>'
RECAPTCHA_PRIVATE_KEY = '<YOUR PRIVATE KEY>'
Save the file. Open .gitignore and add .env. This ensures your secret keys will not be part of the commit so they are not publicly visible in your git repo.
Configuring Views for ReCAPTCHA
First navigate to your controller and edit the create
action to look like this:
#app/controllers/pets_controller.rb
def create
@pet = Pet.new(pet_params)
respond_to do |format|
if verify_recaptcha(model: @pet) && @pet.save
format.html { redirect_to @pet, notice: 'Pet was successfully created.' }
format.json { render :show, status: :created, location: @pet }
else
format.html { render :new }
format.json { render json: @pet.errors, status: :unprocessable_entity }
end
end
end
This will ensure that a new pet object is not created if ReCAPTCHA is not verified.
Let us move to the views.
Open app/views/pets/_form.html.erb and add a reCAPTCHA tag:
#app/views/pets/_form.html.erb
<%= form_for(@pet) do |f| %>
<% if @pet.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@pet.errors.count, "error") %> prohibited this pet from being saved:</h2>
<ul>
<% @pet.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :pets_type %><br>
<%= f.text_field :pets_type %>
</div>
<div>
<%= recaptcha_tags %> <!-- THIS -->
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Start up the rails server (rails s
) and point your browser to http://localhost:3000/pets/new to see reCAPTCHA at work.
ReCAPTCHA and Devise
Devise is a flexible authentication solution for Rails. In this part, I will show you how to integrate ReCAPTCHA with your Devise model.
Add devise
to your Gemfile and bundle install
.
# Gemfile
... other gems ...
gem `devise`
Install devise
:
rails generate devise:install
Next let generate your User
model:
rails generate devise User
Migrate your database
rake db:migrate
We will need to edit devise views so generate that too.
rails generate devise:views
Open your application layout using your text editor and paste this in, just below the body
opening tag.
#app/views/layouts/application.html.erb
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
Integrating ReCAPTCHA
For ReCAPTCHA to work, you will need to edit the create
action in your controller like you did above. We’ll also need to make some changes in the Devise controllers.
Follow me.
Run this generator from your terminal:
rails generate devise:controllers users
This will create a controllers/users folder with all devise controllers contained in it.
Using your text editor, open app/controllers/users/registrations_controller.rb and edit the create
action to look like this:
#app/controllers/users/registrations_controller.rb
def create
if !verify_recaptcha
flash.delete :recaptcha_error
build_resource(sign_up_params)
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
Now navigate to app/views/devise/registrations/new.html.erb and add the ReCAPTCHA tag, so it looks like this:
#app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= recaptcha_tags %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
Now with your browser pointed to http://localhost:3000/users/sign_up you will see ReCAPTCHA in action.
In this tutorial you have learned how to integrate ReCAPTCHA to your Rails application. I felt that adding the bits about Devise might be especially helpful, as it is such a popular gem. Try adding some ReCAPTCHA-based security to your app and let me know how it goes.
I like to write up quick-hitting topics like this one that can be applied immediately with tangible benefit. I hope you enjoyed it.