Advanced Rails Techniques: Beyond the Basics
You master the basics of Rails ? It's time to level up! Let's explore together advanced techniques that will make your code more expressive, maintainable and... "railsy". In this article, we will explore how to use class methods, organize your code with concerns, create your own generators and even extend Rails with custom features.
So what are we waiting for? Let's go :)
The article was written following Chris Oliver's presentation at Rails World 2025, you can find the original video at the end.
What makes the code "railsy" ?
Rails has this unique ability to render code readable as if you were reading a book. Think of methods like has_many :subscribers or has_one_attached :featured_image. It's magic, right? This expressiveness comes from Ruby and the Rails philosophy that your code should stand on an equal footing with the framework itself.
In controllers, we find this same elegance with before_action :authenticate_user. Rails 8 pushes this concept even further with methods like :
These methods visually stand out from the traditional before_action, and that's deliberate !
Create your own class methods Rails
Beyond the before_action traditional
You could write this in your controllers :
But why not do like Rails and create a more expressive class method ?
It's still clearer, right ?
(And on top of that, it’s easier on the eyes than hunting the right before_action in a list of ten !)
Implementing custom class methods
Here's how to create this magic in an authorization concern :
The advantage of class methods ? You can pass arguments! No more creating ten methods for ten use cases.
Organize your code with custom folders
Going off the beaten path
Rails doesn't force you to stuff everything into models, views and controllers. You can create your own folders in app/ :
- app/api_clients/ for your API clients
- app/ui_components/ for your UI components
- app/validators/ for your custom validations
- app/notifiers/ for your notifications
- app/services/ for your services
Rails will automatically load these folders. It's like having a drawer for every type of utensil in your kitchen! This will make your code so much nicer to read and maintain.
Concrete example: custom API clients
Instead of using an external gem that implements 200 endpoints of which you only need one, create your own client :
Simpler, more maintainable, and zero external dependencies!
Custom Rails generators
Creating your own tools
Rails lets you create your own generators. It's perfect for standardizing patterns in your team :
This creates a generator that inherits from NamedBase, automatically handling arguments and file paths :
Customize existing templates
Are you still using scaffolds to make your life easier? But you’re tired of <%= notice %> when you already have it in your layout ?
Well, easy Monique. Override the template :
Now your scaffolds adapt to your application !
Concerns for organization, not just reuse
Organize by feature
Concerns aren't just for sharing code. You can, and some would say you should, use them to organize models by feature :
These modules live in app/models/user/ and contain all the logic related to each feature. No more 500-line models where everything gets mixed!
A complete example: Cloudflare Turnstile integration
What is Cloudfare Turnstile
Cloudflare Turnstile is a modern alternative to traditional CAPTCHAs (you know, those annoying tests where you have to identify traffic lights or crosswalks 😅).
The problems it solves:
- Bots : Automated programs can spam your forms, create fake accounts, etc.
- Traditional CAPTCHAs : Frustrating for users, sometimes hard to solve, not always accessible
Turnstile verifies that the user is human in an almost invisible way. It analyzes the browser's behavior in the background, without bothering the user with puzzles. It's free and more privacy-friendly than reCAPTCHA.
The initial problem
You want to integrate Turnstile into your signup form. First instinct :
Why is that frustrating ?
Imagine this scenario :
- A user fills out your signup form
- They forget to fill in their email (validation error)
- They submit the form
- Turnstile passes (it's human), but the email is missing
- The form reloads with the error "Email required"
- They add their email and re-submit
- New Turnstile challenge ! 😤
The Turnstile token is single-use. Each submission = a new challenge.
The elegant solution
Create a reusable concern :
- attr_accessor :challenge_token : Creates a temporary attribute (not in the database) to store the Turnstile token
- validates :challenge_token, turnstile: true : Adds a validation that checks the token with Cloudflare
Why a concern ? You can easily add it to any model (User, Comment, ContactForm, etc.)
Now create a custom validator
What happens :
- Rails automatically calls this validator when you do @user.save
- It checks the token with the Cloudflare API
- If it fails, it adds an error like any other validation
Now in your model :
One line, and your User has Turnstile protection now.
And your controller becomes simple again :
Extending Rails with template handlers
The idea
Rails uses a system of template handlers to process different formats. index.html.erb ? The ERB handler processes the file. index.json.jbuilder ? It's the JBuilder handler that handles it.
You can create your own handlers ! (Well, the PHP example in the talk was... let's say... "original", but the principle remains valid.)
Practical example: Farem PDF
Here's a more serious example with the gem Farem PDF that generates PDFs without Node.js :
The custom renderer :
- Captures the rendered HTML
- Launches Chrome in headless mode
- Generates the PDF
- Returns it to the browser
All of this in a transparent way !
Conclusion
These advanced techniques transform Rails from a web framework into a true domain language. By using the class methods, organizing by concerns, custom generators, and Rails extensions, you create a code that tells a story and reads like a book.
The secret ? Don't be afraid to extend Rails as needed. The framework is designed to be customized, so take advantage of it! And remember : if your code doesn't read like English, there's probably a more "railsy" way to write it.
The original presentation by Chris Oliver:
Rails Ascent