Roll Your Own Ruby Framework

Patrick J. Sparrow
Broadlume Product Development
4 min readJan 23, 2020

“We run Hanami in production!” Our Vice President of Engineering, Justin Jones, included this statement in a job posting and in his lightning talk at RubyConf. Technically, it is a true statement. FlooringStores.com runs on Hanami! Hanami is an alternative framework to Ruby on Rails, and working with it has made me realize that web application frameworks do not have to be overly complex.

Hanami means “flower viewing” in Japanese

As I thought about it more, I realized that we have made some heavy modifications to the default configuration for a Hanami application. Early in the project, we replaced the model layer with direct usage of Rom-sql. This allows us to pass around relations and lazily perform database queries. We also modified the view layer to support server-rendered React.

So, although we use Hanami in production, we mainly use the router and controller layer and could probably swap those out for another framework in the future without too much of a headache. This led me to think about what it would take to build a Ruby application without a framework.

Every developer toys with the idea of building an MVC (model-view-controller) framework. It’s a great learning exercise that provides insight into and appreciation for robust frameworks like Ruby on Rails. However, it’s usually written off as reinventing the wheel when applied to real-world projects. On the other hand, given the quality of libraries in the Ruby ecosystem today and the way Rails apps tend to age, building your own application-specific framework might be a perfectly acceptable solution.

Assuming a basic knowledge of the model-view-controller architecture, this post introduces some options for fulfilling the main responsibilities of a Ruby MVC framework.

What are the responsibilities of a Ruby MVC framework?

An MVC framework accepts a web request, executes some code, and returns a response. Assuming the framework is rack-based like nearly all Ruby frameworks, the main responsibilities include routing the incoming request to a controller that interacts with models and typically renders a view or redirects to another URL.

Routing

Routing involves mapping an incoming request to the code that handles that request. Various properties of the request such as headers, method, path, and parameters could affect how the request is routed.

Roda is a powerful routing framework that supports nested routes, type checking, and blocks for handling requests.

Example Roda Code

Sinatra is framework that supports namespaces and provides a clean DSL (domain-specific language) for routing.

Example Sinatra Code

Through core features or extensions, both provide support for sessions, cookies, and even template rendering.

Models

The model layer is responsible for managing all interactions with the database. These include basic CRUD operations (create, read, update, delete) and may include advanced features such as migrations and schema dumps.

Sequel is a great library that supports model classes in addition to all common database interactions.

Example Sequel Code

Rom-rb is an implementation of the data mapper pattern that separates relations, repositories, and entities. Its Rom-sql library is built atop Sequel.

Example Rom-rb Code

Views

Views are responsible for displaying content to the visitor. They are typically used to embed data provided by the controller into HTML or JSON documents.

ERB is a templating system built into Ruby’s standard library. It’s also the default templating system for Ruby on Rails.

Example ERB Code

Tilt is a templating system that provides a generic interface that supports all common templating languages. Here’s an example using tilt to render a liquid template.

Example Tilt Code

Controllers

Controllers contain the code that handles incoming requests, interact with models, and render views. Because both Sinatra and Roda take blocks that handle incoming requests, building separate controllers may be unnecessary.

You can place the code that handles the request directly within each routing block. However, moving the business logic into separate classes may be easier to test and manage as the application grows. Below is a simple example, but it’s easy to imagine a base class that handles validation and error message formatting.

Example Sinatra Routing Block Code

These are just a few options for building your application with stable, powerful libraries without the giant footprint of Ruby on Rails. If you’re not up for building your own framework from scratch, you may want to consider checking out Hanami. We found it to be a flexible alternative to Rails that was easy to customize to meet our needs. Feel free to reach out if you have any questions!

Hi there, I’m Pat and I’m currently a Lead Software Engineer at AdHawk. We are working on a variety of exciting new technologies and applications and are always looking for talented engineers to join our fast-growing team. Take a look at our job board and apply today -> https://www.tryadhawk.com/jobs/

--

--