Keeping each layer of your application contained can be a difficult task, especially given the expressiveness of templating languages today.
One thing that has bitten me more than a few times is that, within a Rails application, rendering a template will often have side effects. Specifically, you’ll accidentally head back to the database to pull some more information out to be rendered in the template. This can be a silent killer for performance, and is difficult to track down.
Ideally, rendering a template would be a pure function. Given the flexibility of ERB, this is not always the case:
Depending on the code within your controller, you may incur database requests within your template. Such non-determinism can make performance issues difficult to track down.
If your controller looked like the following:
class BlogsController < ApplicationController def show @blog = Blog.find(params[:id]) end end
Rails will issue the following request within the template to populate the list of blog posts:
SELECT "posts".* FROM "posts" WHERE "posts"."blog_id" = $1
Such behavior is definitely less than ideal.
To solve this problem, I put together a gem called
strict_templates. After installation, it
will error hard whenever the database is accessed from a template. All it takes is a new line in your Gemfile
And then including a simple Concern:
class ApplicationController < ActionController::Base include StrictTemplates::Concern end
In my previous
BlogsController snippet, a new
SQLPerformedWithinTemplateError will now get raised when the template pops off a database request. To move the database request out of the template and into the controller, we change our code to eagerly load the association:
class BlogsController < ApplicationController def show @blog = Blog.includes(:posts).find(params[:id]) end end
strict_templates is designed to give some bumpers for teams to keep their models, views, and controllers separate.
This is still a young gem and is a work in progress. I’ve tested it on Rails 5. Your mileage may vary with other versions of Rails.
The problem addressed by this gem could also be avoided entirely by choosing a less expressive templating language. For existing teams on large projects, swapping out a templating language is not an easy task. That’s why this is packaged as a concern: you can slowly mix it into controllers before pulling the dependency up to your