Without veering too far off topic here, what I’m trying to get at here is this: we can learn a lot from observing how other frameworks (and even other languages!) handle their code when things get messy. I’ve come to respect Ember a lot over the past few months, and one of the many reasons I do is because of how the framework handles encapsulation. Ember has a pretty fantastic way of packaging up view logic into a single, standalone piece of code known as a component. Ember components are powerful because they can be rendered as many times as you need, and contain the logic for how something should appear. This means that we can iterate through an array of objects and render the same component, an encapsulation of how that object should appear, and only change the code in one place should we need to do so. I love how components work, and I’ve wistfully longed for a way to do something similar in Rails views. It turns out that someone else also wanted the same thing I did, except that he actually built it — thank you, Nick! And now we get to play with his creation, which is aptly called the
Components of A Cell
cells gem is packed with a cornucopia of functionality. Seriously: it does so many things — all the things! But before we go down the path of all the bells and whistles that this gem provides us with, it’s important to understand what it is meant to do at its most simplest level.
So much of the time, our Rails views are the first files to devolve into a complete and utter mess, with
else conditional statements in slim or erb that make it hard to read and really shouldn’t even belong there. But at the same time, we don’t really want to put them in our controller either, and it seems strange to make a model responsible for knowing how to present itself (and effectively blur the lines between the Model and View in a MVC framework). As it stands, partials and helpers are the only good solution to this problem, but they’re not really “good” solutions by any means.
Rails views are meant to be dumb — that is to say, they shouldn’t be responsible for determing the logic for how to render anything. Theoretically, you should just pass them some information, and they should spit it out in the correct format. But with partials, this can easily get out of control; we quickly end up with “decider logic”, or some sort of conditional statement that determines how the view should render itself. If we get a little queasy just thinking about this, that’s a good thing: logic should live in a class, not a view of any kind!
And that’s where the
cells gem comes in. At its core, it gives us an easy way to create a kind of Ruby object that has a single responsibility: rendering a template. Yup, you read that correctly: an object that renders a view. Or, as the documentation refers to them, view models:
“Think of cells, or view models, as small Rails controllers, but without any HTTP coupling. Cells embrace all presentation and rendering logic to present a fragment of the UI. The scope of that fragment is up to you: it can embrace an entire page, a single comment container in a thread or just an avatar image link.”
So far, this isn’t anything too complicated, right? But what does this look like in practice? Let’s take a quick peek.
In our bookstore application, we have a navigation panel that the user sees when they log in. We’ll probably have a button or tab that will reveal past addresses that are associated with the current user’s account. The annoying thing about addresses is that we probably want to format them different, depending on whether they have two street addresses (think apartment number, suite, etc.), or if they have an international address, or maybe for some other edge case that we haven’t even run into or considered quite yet. Ultimately, it would be pretty great if we could just take all the logic of how and whether to render an address and pass it off to an “address component” that would be responsible for handling this.
cells API, we can do exactly that. And this is what it would look like in a template, using a helper:
The cell method takes two arguments here, the first of which is a symbol and effectively tells the method where to look for the object that will be responsible for rendering our
@address instance. And the second argument is the
@address instance itself. The helper above is actually calling this method invocation under the hood:
Things start to get really fancy when we start using the same cell to render a whole bunch of addresses. In fact, we can actually just pass off a whole collection of addresses to our cell, which then allows us to use our cell helper inside of our
1 2 3 4 5
This might seem kind of strange at first, but once we let go of the comfort that is Rails convention, we might realize something: this is just nothing more than object-oriented programming! We have an object that has a single reponsibility: rendering a view. In a way, this is pretty darn Ruby-eqsue, isn’t it? If we can encapsulate a unit of work into a service, why not capture a piece of functionality into an object, especially if that functionality is going to be repeated in our application multiple times!
Okay, so how exactly does this model somehow render a view? We need to know how this magic happens! It’s time to put these cells under the microscope and compose a cell ourselves.
Cells Under A Microscope
Getting set up with
cells is pretty straightforward. First and foremost, we’ll need to add
gem 'cells', "~> 4.0.0" to our
One important thing to remember is that this gem supports various templating engines, but it’s actually up to us to specify which one we plan on using. In our case, we’ll stick to simple erb, which means we’ll need to add
gem 'cells-erb' before we can run
bundle. Other templating options include Haml (
gem 'cells-haml') and Slim (
gem 'cells-slim'). As long as we’re using Rails, this is all we need to do. However, if we want to add cells to a Ruby project that is not using Rails, we’ll need to specifically include the templating format in our Cell class (for example,
But we’ll stick with our Rails cell for now. We can very quickly create a cell by using a handy generator and run a single command to create our address cell:
This will create a few things for us. First, it will generate a cell model at the path
app/cells/address_cell.rb. It will also create a view template at
app/cells/address/show.erb. The structure of these files is crucial, since the call method will lookup the correct template from the correct cell model, and expects everything to be structured according the name of the cell we’re specifying.
Now we can get down to some cellular business. Let’s take a closer look at our cell model, at
address_cell.rb. Here’s what it starts off as:
1 2 3 4 5
show method (our only method at the moment), maps to the
address/show.erb file that is our actual view. This method calls
render, which will invoke rendering for the
This is a cell at its most basic level, and theoretically, it’s all you really need for it to work. However, we can start to get fancy here and add properties, and private methods that we might want to use in our view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
We have access to the cell’s model in this context via its attribute reader; we can read the value of the model’s attributes by using
property. This simply delegates to the attribute on the model itself, which means that
property :user merely delegates to
model.user. It’s worth mentioning that our model is the very same instance that we passed to our cell helper — in this case, our
Now that we have our cell model ready to go, we can write our view. We can put any rendering logic into this single view, and render it accordingly. More importantly, if we want to change how all our addresses are rendered, we can just change the logic in one place:
1 2 3 4 5 6 7 8 9 10 11
And what if we decided to have another cell template that was less detailed, perhaps one that would map to an
index action in our
AddressCell model? We would simply create a
1 2 3
And make sure that it mapped to an
index action in our
1 2 3 4 5
Which would allow us to call it using the call style, where we could specify the action that we wanted to call:
In this case, because we’re not using the default
AddressCell#show action, we need to explicitly specify which action in our model we want to call. But we can still reuse our cell over and over again for different situations, which is super cool!
Cellular Tips And Tricks
It’s hard to cover everything that the
cells gem does without rewriting the documentation, but there are a few interesting tricks up this gem’s sleeves that seem like they’d be fun to play with.
So far, we’ve been using the cell helper to render a single object instance at a time. But earlier, we had wanted to pass a collection of
Address instances to a controller action. There’s an easy way to do this by passing the
collection option to the
cell method. Rather than the second argument being an instance of
@address, we can pass a collection of
This will by default call the
show method for each of the addresses associated with the
current_user. If we wanted to use our
index action to instead render our
address/index.erb per address instance, we can specify this by using the
One of the default behaviors of
cells is to not escape any HTML, at any point. But, if we had a property that was actually going to return HTML that needed to be converted to escaped strings, we could simply include the
1 2 3 4 5 6 7
HTML escaping is fairly well-explained in the gem’s documentation.
The super awesome thing about the
render method is that it’s not complicated, at all. There are multiple ways of writing the same thing. If we’re rendering the
show method, we can simply call
1 2 3
And if we’re rendering something other than
index, we can either tell the method the name of the template to render, or specify which view to render:
1 2 3 4
The only other piece of functionality we would need to pass to the
render method is locals, which can be passed in as a hash to the method directly:
So easy to write and remember!
It’s also worth noting that I only just learned about this gem, which means that I haven’t played around with it a whole lot. There’s probably many different ways to go about implementing it, some of which will be specific to a given application. But, it’s worth exploring to see if it’s a useful tool for replacing some ugly, repetitive view logic you might have polluting your codebase. And whether you decide to add
cells to your application or not, it’s still pretty cool to see how people in our community are taking concepts and techniques from other frameworks and languages and applying them in interesting ways to Rails. To me, it’s a good reminder that we should never stop examining other ways of doing things — even if that means subjecting ourselves to more semicolons that we might like!
- A cell is a Ruby object that can render a template, which becomes a powerful form of encapsulation. By default, its call to
renderwill proxy to the object’s
showmethod, but can be overriden if necessary. Read more on the gem’s Github page.
cellsgem is one the most well-documented ones I’ve seen. The documentation covers everything, from the basics of its API, as well as how to test, cache, and troubleshoot the gem.
- Nick Sutterer, the author of
cells, wrote a great blog post highlighting the best practices of the gem’s implementation in Rails. Check it out over here!