使用gem rucaptcha

目标

步骤

Step 1

依照README步骤,将rucaptcha加到Gemfile:

+ gem 'rucaptcha'

创建档案,输入指令如下:

touch config/initializers/rucaptcha.rb

并填入如下内容

RuCaptcha.configure do
  # Color style, default: :colorful, allows: [:colorful, :black_white]
  # self.style = :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
end

Step 2

自定义devise,参考rucaptcha的wiki教程

首先先把devise的controller叫出来:

rails g devise:controllers users

自定义registration的controller如下:
app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  def create
    build_resource(sign_up_params)
    if verify_rucaptcha?(resource) && resource.save
      yield resource if block_given?
      if resource.persisted?
        if resource.active_for_authentication?
          set_flash_message! :notice, :signed_up
          sign_up(resource_name, resource)
          respond_with resource, location: after_sign_up_path_for(resource)
        else
          set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
          expire_data_after_sign_in!
          respond_with resource, location: after_inactive_sign_up_path_for(resource)
        end
      else
        clean_up_passwords resource
        set_minimum_password_length
        respond_with resource
      end
    else
      clean_up_passwords resource
      respond_with resource
    end
  end
...(略)
end

把devise的view叫出来,在终端输入:

rails g devise:views users

自定义registration的view如下:
app/views/users/registrations/new.html.erb

...(略)
<div class="form-inputs">
  <%= f.input :email, required: true, autofocus: true %>
  <%= f.input :password, required: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %>
  <%= f.input :password_confirmation, required: true %>
+  <%= rucaptcha_image_tag(alt: 'Captcha') %>
+  <%= rucaptcha_input_tag(class: 'form-control', placeholder: '请输入验证码') %>

</div>
...(略)

修改routes如下:
config/routes.rb

Rails.application.routes.draw do
...(略)
- devise_for :users
+ devise_for :user, controllers: {  
+   passwords: 'users/passwords',
+   registrations: 'users/registrations',
+   sessions: 'users/sessions'
+ }
...(略)
end

http://localhost:3000/user/sign_up 尝试注册一个新的帐号,但验证图片没有显示出来:

右键点破掉的图片,到这个链结 http://localhost:3000/rucaptcha/

出现如下报错:

安装gem dalli

bundle install

重启rails s

再次注册,但填写验证码正确还是无法注册的话,检查rails s的logs是否有类似如下的错误:

如有的话,请依照如下步骤排错:

在终端输入

brew install memcached

brew services start memcached

重启rails s即可。

Step 3

一样的步骤修改登入
app/controllers/users/sessions_controller.rb

class Users::SessionsController < Devise::SessionsController
  prepend_before_action :valify_captcha!, only: [:create]

  def valify_captcha!
    unless verify_rucaptcha?
      redirect_to new_user_session_path, alert: t('rucaptcha.invalid')
      return
    end
    true
  end
...(略)
end

app/views/users/sessions/new.html.erb

...(略)
<div class="form-inputs">
  <%= f.input :email, required: false, autofocus: true %>
  <%= f.input :password, required: false %>
  <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
+  <%= rucaptcha_image_tag(alt: 'Captcha') %>
+  <%= rucaptcha_input_tag(class: 'form-control', placeholder: '请输入验证码') %>
</div>
...(略)

http://localhost:3000/user/sign_in 测试看看

对以上操作有疑问,可参考YY repo:
https://github.com/yungyuan/jdstore/tree/rucaptcha

Step 4

请自己实际操作找回密码
提示:更改以下两个档案
app/controllers/users/passwords_controller.rb
app/views/users/passwords/new.html.erb

Step 5 Rucaptcha + heroku

如要上传到heroku,请依照如下设置操作:

git checkout -b rucaptcha-heroku

在heroku上启用memcachier这个服务:
heroku addons:create memcachier:dev

移除原来的rucaptcha.rb
mv config/initializers/rucaptcha.rb config/initializers/rucaptcha.rb.temp

并在 config/environments/production.rb 修改如下(最下面end以上找地方加即可):

    
Rails.application.configure do
...  (略)
      
+ config.cache_store = :dalli_store,
+                       (ENV["MEMCACHIER_SERVERS"] || "").split(","),
+                       {:username => ENV["MEMCACHIER_USERNAME"],
+                        :password => ENV["MEMCACHIER_PASSWORD"],
+                        :failover => true,
+                        :socket_timeout => 1.5,
+                        :socket_failure_delay => 0.2,
+                        :down_retry_delay => 60
+                       }

...  (略)
end

保存修改

git add .

git commit -m "change config for rucaptcha/dalli on heroku"

上传到heroku

git push heroku rucaptcha-heroku:master

具体作法可参考repo: https://github.com/yungyuan/jdstore/tree/rucaptcha-heroku

备注:如此一来,本地上的rucaptcha将无法使用,所以这个设置只能适用heroku。要两边都能适用,请依照JDStore部署到heroku的类似方式修改。