Awesome Open Source
Awesome Open Source


Gem Version build

This is a Captcha gem for Rails Applications which generates captcha image by C code.

NOTE: According to the use of Ruby China, the verification code looks like has a lower than 5% probability of being parsed by OCR and the verification code is cracked. It is recommended that you use the IP rate limit to enhance the protection. NOTE: Ruby China 5% OCR IP



  • No dependencies. No ImageMagick. No RMagick;
  • For Rails Application;
  • Simple, Easy to use;
  • High performance.


Put rucaptcha in your Gemfile:

gem 'rucaptcha'

Create config/initializers/rucaptcha.rb

RuCaptcha.configure do
  # Color style, default: :colorful, allows: [:colorful, :black_white]
 # = :colorful
  # Custom captcha code expire time if you need, default: 2 minutes
  # self.expires_in = 120
 # [Requirement / ]
  # Store Captcha code where, this config more like Rails config.cache_store
  # default: Read config info from `Rails.application.config.cache_store`
  # But RuCaptcha requirements cache_store not in [:null_store, :memory_store, :file_store]
 #  Rails  cache_store 
 #  [:null_store, :memory_store, :file_store]  RuCaptcha  cache_store
 self.cache_store = :mem_cache_store
  #  disable cache_store  warning truedefault false
  # self.skip_cache_store_check = true
  # Chars length, default: 5, allows: [3 - 7]
  # self.length = 5
  # enable/disable Strikethrough.
  # self.strikethrough = true
  # enable/disable Outline style
  # self.outline = false

RuCaptcha Rails Session Rails Session Cookie Replay attack

RuCaptcha Memcached Redis cache_store

:file_store tmp/cache/rucaptcha/session

cache_store Rails Guides Memcached Redis

(RuCaptha do not use Rails Session to store captcha information. As the default session is stored in Cookie in Rails, there's a Replay attack bug which may causes capthcha being destroyed if we store captcha in Rails Session.

So in my design I require RuCaptcha to configure a distributed backend storage scheme, such as Memcached, Redis or other cache_store schemes which support distribution.

Meanwhile, for the ease of use, RuCapthca would try to use :file_store by default and store the capthca in tmp/cache/rucaptcha/session directory (kindly note that it's not working if deploy on multiple machine).

For recommendation, configure the cache_storemore details on Rails Guides Configuration of Cache Stores to Memcached or Redis, that would be the best practice.)

Controller app/controller/account_controller.rb

When you called verify_rucaptcha?, it uses value from params[:_rucaptcha] to validate.

class AccountController < ApplicationController
  def create
    @user =[:user])
    if verify_rucaptcha?(@user) &&
      redirect_to root_path, notice: 'Sign up successed.'
      render 'account/new'

class ForgotPasswordController < ApplicationController
  def create
    # without any args
    if verify_rucaptcha?
      redirect_to '/forgot-password', alert: 'Invalid captcha code.'

TIP: Sometimes you may need to keep last verified captcha code in session on verify_rucaptcha? method call, you can use keep_session: true. For example: verify_rucaptcha? @user, keep_session: true.

View app/views/account/new.html.erb

<form method="POST">
  <div class="form-group">
    <%= rucaptcha_input_tag(class: 'form-control', placeholder: 'Input Captcha') %>
    <%= rucaptcha_image_tag(alt: 'Captcha') %>

  <div class="form-group">
    <button type="submit" class="btn btn-primary">Submit</button>

And if you are using Devise, you can read this reference to add validation: RuCaptcha with Devise.

Write your test skip captcha validation

for RSpec

describe 'sign up and login', type: :feature do
  before do
    allow_any_instance_of(ActionController::Base).to receive(:verify_rucaptcha?).and_return(true)

  it { ... }

for MiniTest

class ActionDispatch::IntegrationTest
  def sign_in(user)
    post user_session_path \
         'user[email]'    =>,
         'user[password]' => user.password

Invalid message without Devise

When you are using this gem without Devise, you may find out that the invalid message is missing. For this case, use the trick below to add your i18n invalid message manually.

if verify_rucaptcha?(@user) &&
  redirect_to someplace_you_want
  # this is the trick
  @user.errors.add(:base, t('rucaptcha.invalid'))
  render :new

Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
C (276,169
Security (8,713
Captcha (602
No Dependencies (336
Recaptcha (307
Related Projects