While Sinatra’s one-file approach may work well for your one-off, smaller
application – it can quickly become a mess as you add on multiple routes,
route-handlers, helpers, and configuration. So what’s a programmer to do?
In reading Sinatra’s documentation I’ve found a few morsels that have enabled
us to split our otherwise-monolithic (I realize this term is becoming a cliché,
but given the single-file nature of Sinatra-based web-applications I feel like
it’s appropriate) applications into smaller, more manageable pieces.
The “Classical” Sinatra Application – Our Baseline
We’ll start with something paired down for simplicity’s sake. I’ll leave it as
an exercise to the reader to determine what this application does and instead
focus on code-style and organization.
Use Sinatra’s “Modular” Style
According to the Sinatra docs: “When a classic style
application is run, all Sinatra::Application public class methods are exported
to the top-level.” Also, using the classical style prevents you from running
one Sinatra application per Ruby process – all
calls to these top-level methods are handled by Sinatra::Application,
functioning as a singleton. We can avoid these potentially-confusing scoping
problems by reorganizing our application into what Sinatra calls the “modular”
style, like so:
This app will need to be started with rackup via a config file (I called it
“config.ru”) that looks something like:
Reduce Duplication via Lambdas
One thing you may find yourself wanting to do is bind multiple routes to the
same handler. While there’s nothing keeping you from factoring this shared code
into a method invoked in each route-handler’s block – it would be nice if we
had some clean, concise way to remove the duplicate blocks entirely. Using
lambdas passed as blocks, you can visually separate routes from their handlers
and share the handlers across routes with ease.
Break Your Code Into Multiple Files
As your application grows larger (in line count) you’ll most likely want some
way of grouping together pieces of like-functionality into separate files which
are then required by your main Sinatra-application’s file. This can be achieved
using the “helpers” and “register” methods, like so:
These are just a few tips and tricks that you can use in your next
Sinatra-based project. We’ll keep posting as we learn new ways to simplify and
organize our code – so stay tuned!
In the mean time, I encourage you to review the Sinatra
documentation and the excellent Sinatra
Explained project by Zheng Jia.
Be sure to check out Sinatra Best Practices: Part Two.
This article was co-written by Travis Herrick and Erin Swenson-Healey.