Using Routing Constraints to Root Your App
Zachary Porter, Former Senior Developer
A few months ago as a part of Pointless Weekend, a small group of us in Viget South set out to create a score-keeping app that would later be known as OfficeGames. The app came together quite nicely and a few of us use it to keep track of high scores around the office. However, this article is not about the shameless self-promotion. Rather, this article will describe one tiny little feature that is pretty cool: setting a root path depending on whether a user is logged in.
You have probably seen this feature before. A logged-in user is sent to a dashboard or, in the case of OfficeGames, to the listing of games. It's pretty standard stuff. In OfficeGames, the default root path points to the registration page. This root path is used as a link in the layout when clicking the logo. Obviously, a logged-in user does not need to be sent to the registration page. A way to send a logged-in user to the listing of games when visiting the root of the site was needed.
There are many ways to accomplish this. One would be setting the root path to the listing of games and redirecting to the login screen if the user isn't logged in. That is fine if a user is logged in, but every time a non-logged in user clicks on a link to the root path, a redirect occurs. Works fine, but not very efficient. Thankfully, Rails provides us with some advanced routing constraints to help. Here's a snippet of the routes file from OfficeGames:
In it, a class for the authentication constraint is defined. According to the Rails Guides, this class needs to define a `matches?` method that Rails uses to determine whether to use this constraint. In the snippet, the presence of a `user_id` in the session object is checked. If this session variable exists, then the constraint should match.
Now in the routes definition, the constraint class is used by calling `constraints(AuthConstraint)` and passing a block to it. All routes defined in this block will be used only if the `matches?` method within the class returns true. Within the constraint block in the example above, the root path is defined as the listing of games. Outside of the constraint block, the root path is defined as the registration page. Simple, effective, and a redirect is avoided.
Note that the root path with the constraint must come before the root path without it. Routes in Rails are matched from top to bottom. The higher a route is, the more precedence it has over routes below it.
What do you think about this approach? In what ways have you used Rails routing constraints? Shout out in the comments below.