This is a real world example how to use Rails Cells, the popular gem for creating reusable view components. The following post is clean and all-ages. Let’s just all be friends, no bashing, no f-words today, just a brief HOWTO.
It is different from what you might have learned from Rails so far. This doesn’t mean it is wrong. Just think about it. If you feel it’s shit, let me know. If you like this approach, I wanna know as well.
What are sidebar elements?
Usually reoccurring components like a “Recent posts” box in a blog application are what we refer to as sidebar element.

The exemplary blog application used in this post(s) can be found on github and runs with Rails 3.
So what we do today is a sidebar box. It contains
- links to a certain subset of recent posts
- tags to click, which will filter the post list
No partials and helpers today
As we’re learning a new paradigm today, we’re not gonna do the traditional approach to implement the box. Using partials and helpers might do it as well, but, let’s look forward.
The first step is to generate a cell, which exposes the same properties as a real controller.
blog$ rails g cells:cell Posts recent --haml create app/cells/posts_cell.rb create app/cells/posts/recent.html.haml create test/cells/posts_cell_test.rb
Ok, a cell class, a view, a test. Great.
In the second step, I want to render a list of recents posts. My file app/cells/posts_cell.rb looks like this.
class PostsCell < Cell::Base def recent @posts = Post.recent render end
Like a controller.
Cells are controllers.
So what do we do here?
- We aggregate the items to display by delegating to the model.
- A call to
#renderinstructs the cell state to render its view inapp/cells/posts/recent.html.haml.
The view is simple as well.
%h3 Recent Posts
%ul
- for p in @posts
%li #{link_to p.title, p}- We simply iterate over the posts and link to the real article.
- Note that we can use helpers, logic, everything in cells views.
As a last step, we render the cell in the application layout.
%body
%h1 The Incredible Cells Blog
#sidebar
= render_cell :posts, :recentThat’s all for creating a render-only sidebar component. You could have done this with your traditional tools. However, we already got a couple of benefits.
- The cell is reusable throughout your project and even between different projects. Just plug the
app/cells/postsdirectory into another app and you’re done. I will post separately about that. - No controller pollution as the cell computes and renders in its own separate instance.
- We have better testability – another post on that one, promised!
Have a tag-cloud widget
One of Cells strength is when it comes to writing composed widgets. The tag cloud sitting above the recent posts list should be a separate cell state – meaning a separate method and a view.
class PostsCell < Cell::Base def recent # ... def tag_cloud @tags = Post.tag_counts_on(:tags) render end end
Not hard to see that we might need another view in app/cells/posts/tag_cloud.html.haml.
- tag_cloud(@tags, %w(css1 css2)) do |tag, css_class|
= link_to tag.name, "?tag=#{tag.name}", :class => css_classYeah, we can even use helpers from other gems, like the acts_as_taggable_on helpers. We’re not limited in any way, dude.
To actually show the tag cloud inside our box, let’s plug the tags into the recent.haml view for now.
%h3 Recent Posts
= render :state => :tag_cloud
%ul
- for p in @posts
%li #{link_to p.title, p}Wow, we basically can embed actions within actions – this is fuc… simply great.
Interaction, babe!
When clicking a tag the “Recent posts” list should update, showing only posts matching that tag. This is something called interactivity – the cell in your controller view processes user gestures!
Not a big deal. And, if you think this is breaking MVC: it is not. This is MVC.
Let’s see how the cell controller handles that.
class PostsCell < Cell::Base def recent tag = params[:tag] @posts = tag ? Post.tagged_with(tag) : Post.recent render end def tag_cloud # ... end
The cell controller is exactly the place where this VC-gluecode should live. We don’t need work-arounds like presenters or helpers here, we prefer true MVC.
Discussion
We just learned the basic usage of Cells, including
- Generating and writing simple render-only cells.
- Composing nested cells by calling
render :statein cell views.
- Processing user input by using
#paramsin the cell state.
And we got plenty of stuff to check out, like
- Caching cells to boost your application performance and simultaneously improving your architecture.
- Writing functional tests and unit tests for cells to create reliable components that can be plugged into any controller and just work!
- putting cells into Rails engines to maximize your modularity. Imagine real widgets for a blog application shipped as gems and running seamless in your views.
Now, comment! And, hey parents: Writing posts without using swearwords SUCKS!

Rymaï
Hey,
thanks, I was waiting for a simple and clear example like this to understand *one of* the benefits of Cells, I may use this in a project refactoring soon, I’ll tell you if it fits my needs (I’m almost sure it does, though, since it exactly the same as this sidebar component example!).
Cheers and congrats for Cells and this simple-but-to-the-point tutorial, I think you really need these kind words after all these *jealous* people that yelled at you!
atros
Rails was so monolithic. Now it’s getting much more modular with Rails3, bundler an cells. We will start to see more and more sharing of small controls. A new era has begun. Great post.
Devise an Conquer!
Jim Gay
Thanks for your work on this, Nick. I’m planning to use Cells in a current project. I’m curious about using this with javascript calls. What if I want to pull in this sidebar via JS?
Are cells routable like that?
Greg
I’ll definitely use Cells in my new projects. Using helpers or before filters to load data for side bar components is very awkward compared to Cells approach.
Jello
Do Cells work with Sinatra?
nick
@Rymaï, @atros, @Jim and @Greg: Thanks dudes, for your nice and motivating comments!
@Jim: What you want is Apotomo. I will release the 1.0 and announce it in a couple o’ days. Lemme know if you run into any trouble!
@Jello: Well, I once worked on that: http://github.com/apotonick/cells-sinatra – do you think this is helpful?
JAlberto
nice article man
jistr
Thanks for Cells, it’s what Rails really missed.
bobanj
Great post, We’ve used apotomo on our last two projects, all the widgets are using apotomo from now on
The reusable thing is really helpful btw.
Less headaches and cleaner code.
Thank You (beer is on me)
Jim Gay
Thanks nick I’ll checkout Apotomo. One thing that stands out about cells is the structure. Why put view files anywhere but in the app/views directory?
The way it is, I anticipate headaches with maintenance for any number of cells over a handful.
Why do cells views live where they do instead of in app/views?
nick
@Jim: Cells are separated in app/cells. Imagine you had a
PostsControllerand aPostsCell– we couldn’t discern between controller and cell views if they were in the same directory.Beside that, we simply don’t like the way Rails organizes the VC assets
What problems do you see in the maintenance?
As a hint, remember you can always do “submodules” like
app/cells/ posts/ form/ recent/where you group views logically in cells. Does that help?
BTW- writing a post how to switch from cells to Apotomo!
Jim Gay
The maintenance problems I see is that we have views in 2 locations. Having an app/cells directory makes sense, but I’d rather organize my views together in app/views/cells (and maybe configurable if that namespace exists).
It’s not a deal-breaker, but it just doesn’t feel right to have views split up.
nick
@Jim: Just do
Cell::Base.prepend_view_path "app/views/cells", how do you like that?angel
can you forget the partials and only works with cells or there’s a reason for keep working with partial??…I don’t like partial, I don’t like his syntax, I don’t like his speed and the ideas behind this…….
nick
@angel: Uhm, the good thing here is, it’s up to you
I personally would not use Cells everywhere, sometimes a stupid partial is simply enough.
As a rule of thumb I’d say use a cell when
stephen murdoch
I’m fixing my sidebar to use cells as we speak and I’m amazed by how much I prefer this approach.
It’s my new favourite gem.
I have a question though, is there a simple rails way to return an array of all the cells in my app? I want to iterate over it
nick
@stephen: Thanks, glad you like it!
Concering your registry-question… hmm. Can’t think of any elegant way right now, I’m afraid you have to search the
app/cellsdirectories. We had aCellRegistryyears ago but then I learned to use Rails’ autoloadingMy recommendation: post this question to the mailing list , there might be a solution around already. Enjoy, and Cheers!
Jonathan Rochkind
Very helpful introduction.
All the examples use a cell in the place you would use a partial view, called from a full view.
Can you also use a cell instead of a top-level view? Can you call render_cell in a controller? And would you want to? I kind of think you might sometimes, although I’m having trouble describing the circumstances.
nick
@Jonathan: You might call
render_cellin a controller, which you could use to replace the top-level view. Some people already do this in order to separate clearly between controller (HTTP, data) and presentation (cell).Rails 3: Common interface elements | Tom Russell – A Ruby/Rails Developer
[...] still on the fence about how elegant this is, and there are other ways of doing this, but I wanted to write something myself — and so far, I’ve not [...]
Andrew
A great gem! I have one issue, I’m using the declarative_auth gem and at some point want to call the permitted_to? method. However this method wants to be aware of the controller in order to obtain the defined authentication rules, is there a way to tell declarative_auth which controller is being referenced?
nick
@Andrew: Thanks! Can you send a link to the permitted_to? method? Maybe you open an issue on github?
Harun
Great work. I am using this on my current project for sidebars and some widgets on main viewport area of the page. Its really working out well. Rails being monolithic was not giving me this freedom and had to write custom code to achieve reusable components.