Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
126 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
ReCaptcha for Rails - With AJAX Validation | ||
========================================== | ||
|
||
Purpose | ||
------- | ||
|
||
This plugin implements view helpers to generate ReCaptcha code, | ||
to interface with the HTTP API for captcha verification, a DSL | ||
to generate a `before_filter` and the necessary hacky code to | ||
implement AJAX captcha validation. | ||
|
||
Implementation | ||
-------------- | ||
|
||
For AJAX validation, a request to ReCaptcha HTTP server must be | ||
made in order to verify the user input, but captchas can be | ||
checked only once. | ||
|
||
The plugin thus, in case of a successful verification, uses | ||
`Rails.cache` to cache the result and then the before filter | ||
checks the cache without issuing a second request to the | ||
ReCaptcha HTTP service. | ||
|
||
Installation | ||
------------ | ||
|
||
script/plugin install git://github.com/Panmind/recaptcha.git | ||
|
||
Gems will follow soon, hopefully after the July 22nd Ruby Social Club in Milan. | ||
|
||
Usage | ||
----- | ||
|
||
In your config/environment.rb: | ||
|
||
Panmind::Recaptcha.set( | ||
:private_key => 'your private key', | ||
:public_key => 'your public key | ||
) | ||
|
||
In your controller, say, the `UsersController` for a signup action: | ||
|
||
require_valid_captcha :only => :create | ||
|
||
private | ||
def invalid_captcha | ||
@user = User.new params[:user] | ||
@user.errors.add_to_base('Captcha failed') | ||
|
||
render :new, :layout => 'login' | ||
end | ||
|
||
The `invalid_captcha` method is called by the plugin when captcha | ||
verification fails, and *must* be overwritten or a `NotImplementedError` | ||
exception will be thrown. | ||
|
||
In your view: | ||
|
||
<%= recaptcha :label => 'Are you human?', :theme => 'clean' %> | ||
|
||
You can pass any `RecaptchaOptions` valid option, as stated by the | ||
service documentation. The only nonstandard option `:label` is used | ||
by the plugin to print a label before the captcha widget. | ||
|
||
|
||
AJAX Validation | ||
--------------- | ||
|
||
To cache the results of a successful captcha verification, a cache | ||
key is needed: this is generated by a `proc` passed to the `:ajax` | ||
option of the `require_valid_captcha` controller method. E.g.: | ||
|
||
require_valid_captcha :only => :create, :ajax => proc { params[:email] } | ||
|
||
This will use the user submitted e-mail as a cache key. When the | ||
form is validated via AJAX, the eventual successful result will | ||
be cached; when the form is submitted, the result will be fetched | ||
from the cache and the signup will continue. | ||
|
||
On Panmind we use our `jquery.ajax-validation` plugin, that you | ||
can download from http://github.com/Panmind/jquery-ajax-nav and | ||
the Javascript code located in the `js/signup-sample.js` file. | ||
|
||
On the backend, an example checker that returns different HTTP | ||
status code follows: | ||
|
||
def signup_checker | ||
if params[:email].blank? | ||
render :nothing => true, :status => :bad_request and return | ||
end | ||
|
||
email = CGI.unescape(params[:email]) | ||
|
||
# more thorough checks on email should go here | ||
|
||
if User.exists?(['email = ?', email]) | ||
render :nothing => true, :status => :not_acceptable and return | ||
end | ||
|
||
unless valid_captcha? | ||
invalid_captcha and return | ||
end | ||
|
||
save_solved_captcha | ||
render :nothing => true, :status => :ok | ||
end | ||
|
||
Moreover, the client Javascript code should be informed via an | ||
HTTP status when validation fails, thus the `invalid_captcha` | ||
must contain a special `render` when the request comes from XHR: | ||
|
||
def invalid_captcha | ||
render :nothing => true, :status => 412 and return true if request.xhr? | ||
# Same invalid_captcha code as above | ||
end | ||
|
||
|
||
Bugs | ||
---- | ||
|
||
The `:ajax` option is clumsy, and should not require the user to pass | ||
a proc with semantics that are closely tied to the method that requires | ||
captcha verification. | ||
|
||
Maybe the `authenticity_token` is a good fit for a validation cache key? | ||
|