Abuse protection
RailsFast ships with several measures you can use to protect against abuse and bots / DDoS / scrapers / bad actors.
Cloudflare Turnstile (Captcha-like)
Cloudflare Turnstile is a widget, like the famous CAPTCHA, that validates whether the user is human or not. This is useful to prevent bots from automatically / massively submitting information to your app, for example.
As we saw in the auth section, all signup/login forms come already protected against abuse by Cloudflare Turnstile.
If you want to add Turnstile (Captcha-like) protection to any other form on any other page, you just need to add the cloudflare_turnstile element to your view:
<%= cloudflare_turnstile(theme: 'dark') %>
And then, in the corresponding controller action:
before_action :validate_cloudflare_turnstile, only: [:your_action]
Everything is configured in RailsFast so that these two lines are enough to add a fully functional Turnstile validation to any form in your app.
Two details worth knowing:
- The
cloudflare_turnstilehelper attaches therailsfast--turnstileStimulus controller that draws the widget and keeps it working across Turbo navigations. If you write the<div class="cf-turnstile">markup by hand instead, adddata-controller="railsfast--turnstile"to it yourself, or the widget never appears and the form is refused. - Inside the Hotwire Native apps the auth forms skip Turnstile on purpose (
validate_cloudflare_turnstile_for_browserinApplicationController): a single-use token would turn every corrected typo on a re-rendered native form into a false "not human" failure.
We leverage the rails_cloudflare_turnstile gem for this, in case you need more documentation in how to use it.
Creating the widget is a dashboard step
The cf CLI has no Turnstile command, so an agent that works only through cf cannot create the widget. Do it in the Cloudflare dashboard:
- Cloudflare dashboard → Turnstile → Add widget.
- Name: your app's name. Hostnames:
example.comandwww.example.com(add your staging hostnames too, if you have them). - Widget mode: Managed. Click Create.
- Copy the site key and the secret key into the
productionblock of your credentials:
production:
cloudflare:
turnstile:
site_key: <the site key>
secret_key: <the secret key>
If your API token has the Account → Turnstile → Edit permission, the raw API call in the Configuration agent lane does the same.
Turnstile turns on only with real keys. Since template v1.15.1, a key that is blank or still the sample's placeholder counts as missing, so a credentials file copied from the sample keeps Turnstile off and the forms work. (The sample's unquoted 0xabc123 reaches the app as an integer; it is recognised too.) Before v1.15.1 the placeholders counted as present: Cloudflare refused every challenge, and nobody could sign up or log in. On an older template, keep the turnstile: block out of your credentials until you have the real keys. bin/railsfast doctor reports a production block still on the placeholders.
Throwaway and mistyped emails
Sign-up and every email change refuse throwaway inboxes and catch typos like gmail.con, with a "Did you mean …?" answer. See Email address checks.
Rate limiting
I recommend setting up any rate-limiting countermeasures in Cloudflare (it's more advanced and kills any request before it actually hits your Rails app), but in case you don't want to / can't do it, you still have a very solid and production-ready mechanisim to easily rate limit requests in your RailsFast apps.
Just add rate_limit to any controller:
class DemoController < ApplicationController
rate_limit to: 3, within: 1.minute, by: -> { current_user.id }, only: :my_action
end
For example, the rule above will block users from submitting more than 3 requests per minute to the my_action endpoint.
Read more about rate_limit in the official RateLimiting docs.
User reports & blocking (opt-in)
If your app has user-generated content or user-to-user interaction, you'll eventually need Trust & Safety primitives: letting users report content and block each other, plus an admin review queue. That's what the moderate gem provides. Uncomment gem "moderate", ">= 1.0.0.beta1" in the Gemfile and follow the moderate README.