Getting rid of before_filter from your ApplicationController with cells
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).
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
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
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
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
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!