Most Rails developers have written apps where you have a marketing homepage and a route that you should be redirected to after signing in. There may even be different pages to be redirected to after signing based on some sort of role system.
Who wants to remember that route across the app? No one.
Instead of writing a nasty helper to determine where to send a user after signing in, let’s have Rails handle this for us.
Enter Rails routing constraints.
It turns out Rack is a beautiful piece of software! With Rails routing
constraints, we can re-use the Rails’
root to handle all this logic for us.
This means no more remembering where
root_url will take you or stuffing all
that logic into some giant switch statement!
For example, I recently wrote an app using Clearance and
visiting the root path without being signed in, I wanted to render high
voltage’s ‘homepage’ view. If the user was signed in, I wanted to display an
administrative page where they could manage their assets.
My routes file looks like this:
root to: "assets#index", constraints: Clearance::SignedInConstraint root to: "high_voltage/pages#show", id: "homepage"
Two roots! My constraint to hitting assets#index is based off my class
Clearance::SignedInConstraint, which I’ve thrown in
# lib/clearance/signed_in_constraint.rb module Clearance class SignedInConstraint def self.matches?(request) request.env[:clearance].signed_in? end end end
This looks to
request.env[:clearance] (introduced in Clearance 0.13), which
Clearance::Session instance, and allows us to call
With Rails constraints, if
.matches? returns true, the constraint is
fulfilled and the router allows assets#index to do its thing. When false, the
route ‘falls through’ and the next root kicks in.
Constraints are a great way to scope routes based on particular preconditions and may end up cleaning up a handful of nasty conditional logic in a view helper. Constraints can be great for things like subdomains as well, but I’d love to hear about some more inventive uses.