Re-using logic in Rails views has long been much more difficult than it needs to be. Any non-trivial web app has stateful UI elements that recur throughout the site like a shopping cart or a navigation area customized for the logged-in user. The need for views that can easily be embedded in other views is pervasive, but the ability to do this cleanly and easily in Rails is simply not there.

Which is why there is, or was, the now-deprecated render_component method. Render_component was conceptually sound – views could be rendered within views using their own controllers – but it was fatally flawed by its need to repeat the entire Rails request cycle, making it intolerably slow.

Many Rails projects resort to partials with before_filters to fill the gap, but such an approach has its own problems. Shared partials bloat the application_helper with their initialization code, and since they can see all of the instance variables of the controller methods that precede them – an unfortunate design decision, I think – they tend to be rife with dependencies on the controllers that initially hosted them, the views that initially contained them, and the helpers that they depend upon. It is rare, in my experience, to find substantial partials that are readily sharable without considerable, painful, debugging to extricate them from the web of dependencies they weave.

Like Rails views themselves, shared partials just don’t feel anything like OOP and don’t provide the clean reusability of real objects, like those found by using ActiveRecord. Which is why there is the Cells plugin.

Cells were created by Ezra Zygmuntowicz, co-founder of EngineYard, father of Merb and all around stellar guy in the Rails world. Recently, they have been brought to release 1.0 status by the work of Peter Bex and Nick Sutterer. Cells make it simple to embed views within views, while maintaining the ability to have a controller that initializes those views and – very importantly – they are fast. In my testing, Cells rendered about 4 times faster than components and rendering 1,000 Cells within a view still netted sub-second response times in a development environment.

[Update, March 25, 2008: Engines is now optional.] Installation of Cells can be achieved by first installing the Engines plugin, which it depends upon for its rendering capabilities. Engines was once scorned for its Rails monkey-patching ways, but its now a well-behaved plugin that offers a number of interesting dimensions of reuse possibilities in its own right.

Create a Rails project and configure a database.yml file in the usual way to see Cells in action.

Next, install right off the trunk of both plugin the project s :

script/plugin install http://svn.rails-engines.org/engines/trunk/ mv vendor/plugins/trunk vendor/plugins/engines script/plugin install http://cells.rubyforge.org/svn/cells_plugin/trunk mv vendor/plugins/trunk vendor/plugins/cells

Cells are conceptually similar to controllers and views, but they are not exposed to Rails routing. They get their own branch in the app tree and no generators exist for them as of this writing, so go ahead and create a folder under app called “cells”.

In that folder, we can create our first cell controller. The naming convention should be familiar. We’ll simply create a file called first_cell.rb. Inside that file, add the following code:

class FirstCell < Cell::Base

def index

end

end

Next, create a sub-folder of cells called “first”, This is where our first cell’s views will live. Depending on your version of Rails, you can call the file “index.rhtml” or “index.html.erb”. Put whatever markup or text you feel like putting in that file.

To generate a regular old Rails view to host this, we can simply do this:

script/generate controller host index

Then, in app/views/host/index.html.erb (or, .rhtml), we can embed our first cell. For kicks, we’ll render it 100 times:

<% 100.times do %>

<%= render_cell :first, :index %>

<% end %>

Launch your Rails app and navigate to http://localhost:3000/host/index and visually caress your fine work. Congratulations, you have discovered Rails view re-use made fast and simple.

Cells require all arguments passed to them, beyond the name of the cell and its action, to be explicit. So, any hash values passed in to a cell are magically added to a hash within the cell called @opts. So, if our cell call became this,

<%= render_cell :first, :index, :some_arg => :some_value %>

that would result in @opts[:some_arg] being populated and available in our first cell controller and views. Cells also allow inheritance and encourage composition by their speed and utility.

Create cells within cells and you can quickly build up a repository of rich interface elements like tree controls, grids, and date pickers using your own home-grown designs or leveraging some excellent Javascript library like Ext, Dojo, jQuery or YUI. Rails developers need not be the poor kids on the block with just a few sparse UI controls, unlike our Java and .NET brethren.

Whether you want your view re-use at the level of page regions or rich UI widgets – or both – Cells can get you there today. Your apps will become instantly more maintainable and you will be able to expand your toolbox to have bigger, better building blocks for the UI’s yet to be crafted in your future.

Resources:

http://cells.rubyforge.org/ (examples are here: http://cells.rubyforge.org/rdoc/index.html)

http://rails-engines.org/

Other interesting developments in Rails view concepts:

http://www.caboo.se/articles/2007/8/23/simple-presenters

http://erector.rubyforge.org/

If you are looking for top-notch Ruby on Rails development and project management with an emphasis on distinctive user experiences, email mike.pence@gmail.com.