How to Add Cloudflare Turnstile to Your Ruby on Rails Application
Adding protection to your Rails app with Cloudflare Turnstile.
tl;dr - the rails-cloudflare-turnstile
gem1 (GitHub link) is a great way to add Cloudflare Turnstile to your Rails app. Let’s learn how to use it!
Setup
First, install the gem:
$ bundle add rails-cloudflare-turnstile
If you haven’t enabled Turnstile yet in your Cloudflare account, follow the “Get Started” guide. You’ll need a sitekey and secret key. Make sure to associate it with your domain too - for instance, kristianfreeman.com
- in the Turnstile settings.
Add your sitekey and secret key to your Rails app - I like to use rails credentials:edit
:
$ rails credentials:edit -e development$ rails credentials:edit -e production
My credentials are structured like this:
cloudflare_turnstile: site_key: foo secret_key: bar
Create an initializer file, called config/initializers/turnstile.rb
:
RailsCloudflareTurnstile.configure do |c| c.site_key = Rails.application.credentials.cloudflare_turnstile[:site_key] c.secret_key = Rails.application.credentials.cloudflare_turnstile[:secret_key] c.fail_open = falseend
Usage
First, we’ll add the Turnstile JS script into an application layout file. If you are super performance-sensitive, you may want to do this specifically on the pages you’re going to use Turnstile. Here, I’ll just add it in app/views/layouts/application.html.erb
:
<head> <%= cloudflare_turnstile_script_tag %></head>
In your forms, you can use the <%= cloudflare_turnstile %>
partial to embed the Turnstile UI element right into your form. For instance, on a signup page:
<div> <%= cloudflare_turnstile %> <%= f.submit t("passwordless.sessions.new.submit"), class: "btn" %></div>
Importantly, you also need to validate on the server-side! Speaking as a CF employee who has talked to the Turnstile team, there is a lot of people implementing Turnstile… without the server-side validation.
Users are created in my app in UsersController#create
. Let’s validate the Turnstile data before calling that method:
class UsersController < ApplicationController before_action :validate_cloudflare_turnstile, only: [:create] if Rails.env.production? rescue_from RailsCloudflareTurnstile::Forbidden, with: :forbidden_turnstile
def create # Implementation of creating users end
private def forbidden_turnstile flash[:error] = "We had a problem creating your account." redirect_to root_path end
If the validation fails, the gem will throw an RailsCloudflareTurnstile::Forbidden
exception. You need to rescue_from
that exception in the controller, and do something with that failure. I prefer not to tell users - they’re probably spammers - that their validation against Turnstile’s rules fail.
Turnstile is great - really easy to configure, and literally saving me money by reducing the strain on my servers and ancillary analytics/marketing products, by reducing the number of junk users being added to my app. It only took ~15 minutes to get this implemented on one of my Rails apps, and I’m already seeing results.
Footnotes
-
Not my gem! But it’s great - thanks to Instrumentl for building it. ↩