Here's a typical scenario I'm facing with nearly every of my projects: I want to render some data in a header, footer or sidebar - like the total number of photos uploaded today, or the latest five reviews that were left on a site, or the latest five blog posts that were published.

Typically, I would solve this with a before_filter in my ApplicationController, fetch my data, assign it to an instance variable, add a partial which renders the data, and then include it in my application's layout.

That's all legit, but I find it kind of ugly to have those instance variables there in the first place, getting auto-magically loaded by the before_filter (I tend to stay away from before_filters for setting things).

I was looking for a betters solution, and I think I found it by making use of the cells gem, which is also part of Trailblazer.

For this example we want to display the latest 5 books that have been created in our application on all pages. The current solution looks like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_filter :load_latest_books

  private

  def load_latest_books
    @latest_books = Book.order(created_at: :desc).limit(5)
  end
end

# app/views/layouts/application.html.erb

<body>
  <%= yield %>

  <h2>Latest Books</h2>
  <ul>
    <%- @latest_books.each do |book| %>
      <li><%= book.title %></li>
    <% end %>
  </ul>
</body>

To get started with cells, we need to add the following two gems to our Gemfile:

1
2
3
4
# Gemfile

gem 'cells-rails'
gem 'cells-erb'

If you're using another template language than ERB, there are also other gems available, like cells-slim, and cells-haml. Now we have a new generator available, which allows us to generate a cell for an individual Book, and one for the LatestBooks:

1
2
rails g cell Book
rails g cell LatestBooks

This will create two new files per invocation: a class inheriting from Cell::ViewModel and a view file. We'll modifying the BookCell:

1
2
3
4
5
6
7
8
9
10
11
# app/cells/book_cell.rb
class BookCell < Cell::ViewModel
  property :title

  def show
    render
  end
end

# app/cells/books/show.erb
<li><%= title %><li>

This will display the Book#title when rendered. Note the property :title line in the cell class - this is basically a shortcut and allows us to simply write title in the view file, instead of model.title.

Next up is the cell for the latest books:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# app/cells/latest_books_cell.rb
class LatestBooksCell < Cell::ViewModel
  def books
    Books.last(5)
  end

  def show
    render
  end
end

# app/cells/books/show.erb
<h2>Latest Books</h2>

<ul>
  <%= cell(:book, collection: books) %>
</ul>

Pretty straightforward again, we simply fetch the latest books, and when rendering we make use of the previously defined BookCell and pass the books collection.

That's enough to insert the following code into our application layout:

1
2
3
4
5
6
7
8
# app/views/layouts/application.html.erb

<body>
  <%= yield %>

  <%= cell(:latest_books) %>
</body>
…

That's all! There's way more than this to cells, for example caching. Stay tuned for more posts on cells and Trailblazer!