Posts Tagged Cells

Pragmatic Rails: Thoughts on Views, Inheritance, View Inheritance and Rails 3.0.4

Thursday, December 23rd, 2010

While hacking on Cells for Rails 3 with Yehuda earlier this year we were discussing if Cells’ view inheritance will be superseded by Rails.Yehuda patiently postponed any work on it with the words “we will do that for you” :-) Apparently, he didn’t lie.

It seems that view inheritance will be available directly in Rails 3.0.4, which is a fantastic improvement for Rails.

In this post I’d like to discuss

  • What is view inheritance and how does it help?
  • What’s the problem when view inheritance is tightly bound to controllers?
  • How shared components with inheritance can help

What is View Inheritance?

Say we have a PostsController in a blog app. It shows a list of posts. Wow. We also have a derived PrivatePostsController, here’s the inheritance chain.

PrivatePostsController < PostsController < ...

Both controllers have an #index method.

class PostsController < ApplicationController
  def index
    @posts = Posts.public_posts_for_all_of_yer
  end
 
class PrivatePostsController < PostsController
  def index
    @posts = Posts.private_posts
  end

While the PostsController does have an index view, its child PrivatePostsController doesn’t.

|-- posts
|   |-- index.html.haml
|-- private_posts
|-- backend

Now, when the private controller wants to render its index view, it first looks in its own views directory. If it can’t find a suitable view, it just travels up the inheritance chain. It finds the parent’s index view, and uses this.

Cool, this is view inheritance.

Inheritance and partials?

The newly introduced mechanism also applies to partials, which is pretty awesome.

If the index view would use a partial to show a list of navigation links, the PrivatePostController could “overwrite” just this piece of the page by dropping a separate partial in its view directory.

|-- posts
|   |-- index.html.haml
|   |-- _navigation.html.haml
|-- private_posts
|   |-- _navigation.html.haml

Overriding view pieces done simple. I’m happy this finally found its way into Rails! Good job, artemave.

Use case: Sidebar widgets

Usually we need shared partials whenever we want a reusable view component.

A sidebar box showing links to unread posts.

What about a status box in our app exposing helpful links to the reader? If an admin user is logged in, he (or her) will get links to edit new, unread posts and his own drafts.

An editor might see links to read new posts assigned to him. His job is just proof-reading.

This is a typical setup in almost every Rails app, small boxes display different informations according to the authenticated user.

Usually this ends up in a helper that delegates to different partials, where lots of code is put into that partials.

def render_status_box
  if current_user.admin?
    render :partial => "shared/admin_box"
  elsif current_user.editor?
    render :partial => "shared/editor_box"
# and so on...

The problem here is, you simply cannot use inheritance anywhere. Neither is it possible to derive helpers (they are modules), nor could view inheritance be applied here.

You can’t inherit shared partials

Why that? Well, the shared partial and the rendering controller are not related in any way. Nevertheless, the controller’s ancestor chain is inspected when trying to find an “inheritable” shared partial, which is simply the wrong place.

In other words, the partial lookup will climb up the inheritance chain of the controller using the partial, and that’s definitly the wrong place to search.

The bottom line: When it comes to reuseable view components, Rails’ view inheritance is still insufficient.

Reuseability with inheritance

So, what do to now? The answer, as usual: Divide and conquer. Split your view into object-oriented components and get back the power of inheritance.

You’re still with me? Cool.

First, I create a cell that provides the basic functionalities – generating a user greeting and compiling a list of links for the user.

class UserCell < Cell::Rails
  def box
    @user_greeting  = user_greeting
    @post_links     = links
 
    render :layout => :box
  end
 
  def user_greeting
    "#{current_user.name} (#{current_user.role})"
  end
 
  def links
    current_user.unread_posts.collect do |p|
      [p.title, post_path(p)]
    end
  end
end

If you’re new to cells, you might read this introducing post.

How to get that in my app?

Now I embedd the cell in the application layout.

  #sidebar
    = render_cell :user, :box

This basically calls the #box state of our UserCell, which

  • compiles the greeting message in #user_greeting. Note how this removes the need for pushing complex helpers into the view.
  • prepares a list of post links in #links. While we could do the setup in the view, too, I prefer placing that kind of code to the controller, since its job is aggregating data. It also improves unit-testability and makes it easy to inherit and override!

The render statement finally parses the cell’s view.

|-- app
|   |-- cells
|   |   |-- user
|   |   |   |-- box.html.haml

The box view could look like this.

  Hey, #{@user_greeting}, how are you?
 
  Check that:
 
  %ul
    - @post_links.each do |p|
      = %li #{link_to *p}

A sidebar box showing links to unread posts.
And we get a list of links pointing to posts which the logged in user hasn’t read, yet. Yeah.

Override a helper, inherit a view!

The admin box shows links for editing posts.

When an admin user is logged in, we want a slightly different list, showing links to edit posts.

Let’s use inheritance to do just that!

class AdminCell < UserCell
  def links
    current_user.pending_posts.collect do |p|
      [p.title, edit_post_path(p)]
    end
  end
end

This is all, we just overwrite the helper. Everything else is inherited from the UserCell. The methods, the states, the views.

No deciders in your views!

Now, your application layout shouldn’t end up with deciders figuring out which cell to render.

#sidebar
  - if current_user.admin?
    = render_cell :admin, :box
  - elsif current_user.editor?
    = render_cell :user, :box

Cells provides you with a builder to prevent your view from being cluttered.

class UserCell < Cell::Rails
  build do |opts|
    AdminCell if current_user.admin?
  end

That’s all! Now, calls to #render_cell(:user, ...) will query the builder and internally create the correct cell for you.

It’s more than a feature

I hope the examples showed how view inheritance can help cleaning up your code while providing an object-oriented view layer with real inheritance. This is nothing exotic – many cells users have reported to use the techniques discussed in this post successfully.

And now, lemme quote my friend Kevin from Austin: Merry Christmas and all that stuff!

Spec your Cells with rspec-cells

Saturday, December 11th, 2010

Today we released rspec-cells 0.0.1 which brings #render_cell to your cell examples.

While we ship Cells with a test case for Test::Unit the RSpec example group for cells has been missing for a long time. Based on Dmytro Shteflyuk’s rspec-cells for RSpec1 we now got support for RSpec2.

Usage

Put the following code in your Rails app’s Gemfile.

group :test do
  gem 'rspec-cells'
end

Just drop your examples into spec/cells/. Here’s how a cell spec could look like.

describe PostsCell do
  render_views
 
  it "should render the posts count" do
    render_cell(:posts, :count).should 
      have_selector("p", :content => "4 posts!")
  end
end

So we basically got a #render_cell for specing which simply returns the rendered markup.

To run your examples we got a rake task.

$ rake spec:cells

Is there more?

Presently, we go without a distinction between controller-only and view-only specs as you might know from controller specs.

Views are always rendered in rspec-cells as in a real functional test.

This is still subject to discussion – if you feel like you could need an explicit way to test your cell class only, or to render your views without executing the state code, let us know.

However, keep in mind that cells should be independent components cutting monolithic controllers into small manageable pieces, and thus might not need to be tested on different layers.

Have fun specing your cells and tell us what you think.

Let’s write a Reusable Sidebar Component in Rails 3!

Monday, November 15th, 2010

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 with a reusable 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 #render instructs the cell state to render its view in app/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, :recent

That’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/posts directory 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_class

Yeah, 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 :state in cell views.
  • Processing user input by using #params in 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!

Rails Misapprehensions: What the fuck is MVP?

Thursday, November 11th, 2010

People usually make me feel slightly embarassed when they ask things like “How does Cells handle MVP?” or, even better, “Is there any MVP implementation in Cells?”.

Frankly, I don’t have a fucking clue about the real differences between MVP and MVC. In the past I usually deflected people’s attention by buying beers instead or whatever. I hope to find some answers in the comments section, soon.

After actually reading a bit about “MVP, Presenters and Rails” I came to the following conclusions:

  • There simply is no difference between MVP and MVC (imho)
  • Rails Presenters don’t implement the MVP/MVC pattern completely (imho)
  • And, if Rails would be real MVC we wouldn’t need Presenters. (imho)

As always, these theses are subject to discussion.

The confusion about MVC and Rails

So the first problem I already discussed in one of my recent posts is that Rails encourages a very monolithic controller architecture having one controller being responsible for a complete page.

As Rails is an opinionated framework, their MVC-definition is absolutely ok for me. However, this is not the MVC known from GUIs – usually you’d have multiple controller-view couples in your page UI, each pair implementing complex elements like forms, menus or pageable lists.

But we already talked about that, I just wanted to point out that this is the root of the mysterious MVP misapprehension in Rails.

MVP, where art thou?

Anybody being seriously interested in GUI design patterns read Martin Fowler’s paper describing MVC, MVP, Presentation model and friends.

To be honest, I still did not understand the difference. Luckily, Martin himself seemed to realize that it is tremendously difficult to discern between the two patterns, and split MVP into Supervising Controller and Passive View (some people alleged that I’m a fan of the latter, which I’m not!).

What I basically get from these excellent writings is that

“Presenters are a loose form of MVC controller. As a result a lot of designs will follow the MVP style but use ‘controller’ as a synonym for presenter.”

which I for myself cut down to MVP == MVC” – at least in a Rails-like web development environment.

It just simplifies things.

Presenters in Rails

In the past years a couple of Presenter implementations emerged and several clever writings about that pattern popped up. I was happy to read Dmytro Shteflyuk’s blog post about his presenter project, although I disagree in some points (I’m an asshole).

The word Presenter obviously refers to the P in MVP, and in Rails they roughly work like this.

class ShowPresenter
  def top_videos
    @top_videos ||= Video.top.all(:limit => 10)
  end

After defining the data aggregating code you can use the presenter in your rendering layer.

<% cache('home/top_videos') do %>
 <%= render 'videos', :videos => @presenter.top_videos %>
<% end %>

So, we retrieve data in the presenter and then pass it to the partial, right? This approach is of course a thousand times better than collecting data for presentation in the view itself.

Help me! What’s a Presenter?

However, in my understanding of the Supervising Controller pattern (which seems to supersede MVP), we need two crucial parts in order to be a Supervising Controller at all:

  • a view to display, well, data
  • a controller to handle input response and complex view logic

Please don’t get me wrong and correct me, I appreciate any approach different from Rails’ traditional VC-stack.

However, to me it seems that presenters in Rails only handle the “complex view logic part” (“collecting the videos to display”), whereas the monolithic ActionController still renders the view and handles input responses.

Am I wrong here? Is the ActionController itself the Supervising Controller which calls a presenter and then renders a view? I’m confused.

Cells is truly MVC, but is it different from Presenters?

After all this confusion and hyperlinking I’d like to stand up for my own solution for this dilemma. Let’s comment Dmytro’s (maybe outdated) blog post where he ponders the benefits of Presenter vs. Cells telling us to use presenters whenever you

  • have too much logic in views
  • get into trouble with already cached data within views
  • can’t test an action anymore because of its complexity

and to use Cells only when

  • you need a reuseable partial with initialization code

Well, I don’t agree here. Cells do all the stuff presenters do, and more. That doesn’t mean you should use Cells everywhere in place of partials and Presenters, but nevertheless comparing Cells and Presenters is discerningly.

Presenters are data aggregators, whereas Cells are autonomous MVC stacks as claimed by the true MVC pattern. This is a bit like comparing controllers with ActiveRecord’s finder.

Presenter gets Cell

Let’s see how the former example would look with a cell.

class ShowCell < Cell::Base
  def top_videos
    @top_videos ||= Video.top.all(:limit => 10)
 
    render
  end
  cache :top_videos
end

The cell would also contain a separate view in its namespace.

Note how simple the actual cell rendering in the controller is since we handle cell caching within the cell itself!

Here, my top porns:
<%= render_cell :show, :top_videos %>

Can you see the difference?

  • Cells can aggregate and prepare data just like presenters in their methods.
  • They keep their views separated, taking away complexity from the monolithic controller
  • Handling caching within a cell drastically reduces controller’s duties and is easier testable, too
  • Both data preparation and rendering is testable in a fine-grained cell scope
  • Cells can also inherit views from parent cells which wouldn’t work with a controller+presenter approach!

By no means do I discourage usage of presenters! Use it, as long as rendering the presented data in the controller scope is clear. If it gets too complex (or if you need any other advantages cells have), use Cells.

MVC, done right

One of my intentions was to show that you don’t need presenters if you have a true MVC framework with multiple controllers/views – you can simply wrap data retrieval, rendering and optimization code (like caching) in a separate controller.

That is how GUIs used to work for decades and how web based frameworks should evolve.

Rails Misapprehensions: Cells don’t break MVC

Monday, November 1st, 2010

I was posting a stupid simple example how Cells can be used the other day. This controversial post got lots of great comments, thanks to all! While some just questioned Cells and its use, a few comments really bashed the project in a very aggressive way. I like that.

The rudeness in some sequential comments seems to come from one cause: Ignorance. The writings simple proof that the author did not understand anything about Cells, and MVC in Rails.

I’ll pick some points from different authors and try to explain.

  • “It messes MVC up.”
  • “a place that also breaks the MVC framework.”
  • “Not only are you abstracting view code out to a place where it simply doesn’t belong, …”
  • “I’m not convinced that the benefits of Cells outweigh the complexity they add.”
  • “I think you are a nut.”

MVC and Rails

Ok, I won’t explain MVC here again. We already got great writings about that – however, there are two points in Rails’ MVC design that might cause confusion.

  • The ActionController mixes MVC and the FrontController , and this creates the impression that web apps have to be one monolithic controller, one view, and maybe a couple of partials rendered in the controller context.
  • Rails hides rendering, so in most cases the programmer doesn’t realize templates rendering happens “in” the controller.

Cells are small controllers, derived from AbstractController. You can imagine them as small, separate MVC-stacks between the traditional Rails VC-layer. There is nothing wrong with that, right, Martin?

At this point I should stress that there’s not just one view and controller, you have a view-controller pair for each element of the screen

(Martin Fowler about MVC, quoted)

How to break MVC?

If calling #render_cell in the controller is “breaking MVC”, why is there a #render, or even a #render_to_string method in the controller? That would mean Rails itself is doing something wrong, as it does rendering in the controller.

It is absolutely ok in the controller to instruct a separate MVC-component to render – as long as the controller doesn’t interfere in the rendering process or even shares knowledge about the cells internals.

What is view code?

First, I’d like to emphasize I never said views should be “dumb, non-runtime-interpreted view code – WTF? I use helpers, logic, everything in cell views.

Complex forms with dozens of fields, computations and conditions are surely not “view code” only, so in my opinion that should be “abstracted out to a place where it simply doesn’t belong”: to a separate component.

However, there is no need to put every little partial to a cell. Don’t do that! It is a matter of feeling to perceive when things are getting too complex for a partial mess and should be refactored to a cell instead.

Cells are more complex

This is absolutely true. Cells bring more classes and assets to your project. It is a new paradigm that wants to be understood. New programmers might be confused of cells suddenly popping up everywhere in your app.

Cells is a new concept in Rails – of course it is more complex than odd partials and helpers accessing global controller variables. It’s a bit like back in the times when OOP became popular and people asked “Why should I use objects when my simple procedures do all I need?“. Cells are object-oriented components (with all the stuff we love about OOP, like inheritance) whereas partials are… whatever.

And, don’t forget Cells can be tested in a very simple and clean way, too. This indirectly reduces complexity.

You are a nut!

True.

I hope this writing clarifies several misapprehensions I created by posting a stupid simple example. Now, fire at will!

Why Rails Controllers need a Double Render

Saturday, October 30th, 2010

In one of my last posts I already discussed the improvements Cells brings to your Rails app by providing view components.

The last day I had an lively discussion about the concept of partials or page fragments in Rails.

Partials make me feel sick. People ordinarily use ‘em in order to have “DRY code”. However, usually the extensive usage of partials makes the architecture even worse.

  • Partials blow up your controllers which should be slim – partials always blindly access variables sitting in the controller, which increases controller complexity and makes your code break often. Just use a non-existent local and you’re knocked out.
  • Partials can’t be rendered in the controller. Unavoidably this shifts code and knowledge to views – isn’t that a so called “NO-GO”?
  • Partials itself can’t be tested separately.

Today I’d like to show one concrete use-case how to really DRY up your view code with Cells.

What’s nice about partials

In our discussion we were refering to a form that was rendered in every action. A Rails developer will put the form in a partial. This is a good thing.

UPDATE: The real form was way more complex! For educational purposes I cut down this example – I wouldn’t implement such an easy task with Cells, Lonny! ;-)

Now we found out we need a customized button title in the form. We have two possibilities at this time.

  • Save the title in an instance variable read by the partial.
  • Pass the title as a local when rendering the partial.

The first is terrible. The second looked like this.

render :partial => "form", 
  :locals => {:title => "Create item."}

And in another view.

render :partial => "form", 
  :locals => {:title => "Update this item."}

The coached colleagues learning Rails asked: “But… isn’t that the opposite of DRY?“ and I said “Yes.”.

Can Helpers help?

We had several identical calls in our views. They started working out different approaches with helpers.

def my_form(title)
  render :partial => "form", #...

Using helpers they were forced to use instance variables, again, for transporting information from controller to view to helper to partial. It was a mess.

Suddenly, someone came up with a new idea: “What if we call the helper in the controller?” – they tried, and failed. Every Rails developer has to meet the DoubleRenderError once in his life.

I interrupted the experiment and introduced Cells getting wet.

DRY up your views!

We simply put the view and associated code in a cell.

class FormCell < Cell::Base
  def display
    @title = opts[:title] or raise "No title passed!"
    render
  end
end

The state view reads the instance variable.

  = form_tag do # ...
 
    = submit_tag @title, :id => :btn

Using instance variables here is ok. Remember, we’re in a small cell instance. You don’t pollute a complete request controller with some rich title.

Even better, we got some options validation, too.

Rendering twice in the controller

As we needed the form in every action, we rendered it in a before_filter. Yeah, Cells can be rendered just anywhere.

  class ItemController < ApplicationController
    before_filter do
      titles = {:create => "Create item", 
                :edit   => "Update this item"}
 
      @form_html = render_cell(:form, :display, 
        :title => titles[action_name])
    end

This is pretty DRY.

  • We define titles and render the corresponding form in one place, as they do go together. We don’t spread a bit code to every action.
  • The controller instance variable contains the rendered form markup.

Naturally, you’re not bound to filters – this is just a simple example.

Testing the form

Being an agile TDD team we instantly travelled back in time and wrote a test before implementing the cell.

class FormCellTest < Cell::TestCase
  test "the button title should be in place" do
    invoke :display, :title => "Test your partials!"
    assert_select "form #btn", "Test your partials!"
  end

Having an object-oriented partial with backing functional test we decided to knock off work for today.

You can find the Cells repo here.

10 Points How Cells Improves your Rails Architecture

Monday, October 4th, 2010

The Cells gem has been around in the Rails community for more than four years now. It has hundreds of pleased users who reported all kinds of use cases and how cells improved their apps. Here’s a compilation of the best practices.

The challenge

A shopping cart in a Rails app.

Usually you’d take a shared partial to display the cart in every controller.

%h1 Your cart
 
- if items.blank?
  = render :partial => "shared/cart/blank"
 
- else
  %ul
    - for i in items
      %li #{i}

Some view would render the cart somewhere.

<%= render :partial => 'shared/cart/cart',
  :locals => {:items => current_items} %>

1. Keep your views dumb

The render :partial looks harmless, and many Railers will argue “Well, you can put that in a helper.” – anyway, this little piece of code alreay contains a lot of knowledge. Too much.

That’s knowing

  • which items to display (current_items)
  • the exact location of the cart partial

A dumb view should not know anything about file locations at all.

<%= render_cell :cart, :display, 
  :items => current_items %>

The CartCell we’re rendering hides any physical file location from us.

2. Don’t put logic into views

Yeah, a snippet like

- if items.blank?
  = render :partial => "shared/cart/blank"
 
- else
  ..

already contains decider logic – didn’t we learn something different from MVC?

class CartCell < Cell::Base
  def display
    return render if @opts[:items].present?
 
    render :view => :blank
end

The cell is supposed to render its display view. If no items were passed, it renders the blank view.

Any decider logic happens in a class, and not in some object-unoriented helper or partial.

3. Interfaces can save lives

So I used :locals in my example above. However, I often see controllers where people just set instance variables and use them throughout all partials.

  def index
    @items = current_items
  ..

The partial blindly accesses instance variables.

  %ul
    - for i in @items

Every controller using that partial has to know which instance variables it has to set before rendering. It’s only a matter of time until some controller renders a partial without providing the queried ivar – and your code crashes.

Cells by contrast force you to define which variables you wanna pass – making you writing interfaces without noticing it.

<%= render_cell :cart, :display, 
  :items => current_items %>

4. Controllers should be slim

So instead of globally cluttering your controller with instance variables, put that into well-encapsulated cells.

class CartCell < Cell::Base
  def display
    @user = session[:user]
 
    render
end

Each cell has a limited scope not polluting anything except itself.

5. Avoid helpers

Helpers are plain modules. And can be pain.

What if the item list in the cart would be sortable? People implement that with helpers.

module CartHelper
  def render_cart_sorted
    order = params[:order] || :asc
    items = @items.sort(order)
 
    render :partial => 'shared/cart/cart', 
      :locals => {:items => items}
  end

This leads me to questioning myself “What is a helper? It’s not a view, but renders. It’s not a controller, but it aggregates data. What are helpers?”.

The answer: Helpers are shit. They completely break anything we learned from MVC and they are untestable.

class CartCell < Cell::Base
  def display
    setup!
 
    render
  end
 
  def setup!
    order = decide_order(params[:order])
    @items = @opts[:items].sort(order)
  end
 
  def decide_order(order)
    order || :asc
  end 
end

Here, sorting (or delegating sorting to the model) is the controller’s job. It’s duty is to process user gestures (user clicks on sorting icon) and to aggregate data (actually sorts data for presentation).

This is called V/C glue code as it lives between view and controller.

Under no circumstances should this be done in a helper.

6. Unit-test your glue code

Brrr, a shiver runs up and down my spine. I just imagined how you’d test this helper code.

With cells, you’d first assure that your sorting is doin’ right.

class CartCellTest < Cell::TestCase
  test "sorting should be doin' right" do
    assert_equal :asc,  cell(:cart).decide_order(nil)
    assert_equal :desc, cell(:cart).decide_order(:desc)
  end
end

Easy. What’s next?

7. Functional-test your rendering

We usually write functional tests when it comes to rendering markup. With helpers and partials this can be really painful.

Cells are made for heavy-duty testing.

class CartCellTest < Cell::TestCase
  test "the cart should look good" do
    @params = {:order => "some bullshit"}
 
    invoke :display
    assert_select "ul li", 3
    ..
  end
end

Cells let you simply test what you just did – in a separate, well-encapsulated environment.

8. Get OOP back in your views

Unfortunately, the current Rails view layer discourages using modern concepts, like inheritance, encapsulation and OOP at all. Why?

Why should we have great models and sucky views?

Now imagine it’s getting christmas, and your cart should look christmessy. Like some snowflakes in the background and a smiling reindeer on the order button.

class XmasCartCell < CartCell
  def display
    setup!
 
    render :layout => 'xmas'
  end
end

We simply inherit

  • the setup methods
  • the behaviour
  • the views

It’s just OOP, back in your views. No magic, no implicit syntax, just OOP from the book.

9. Teams love components

Mando works on the shopping cart, whereas Charles plays around with the bestseller cell. Both are working on features shown in the same controller.

However, Charles and Mando will never get into trouble with each other – both have a separate component which does not know anything about the outer world.

Mando is strictly bound to

app/cells/
         cart_cell.rb
         cart/
             display.haml
             order_button.haml

Charles codes somewhere else in

app/cells/
         bestseller_cell.rb
         bestseller/
                   list_latest.haml

They have separate tests, too. And when they think they’re stable they just plug the cells in the controllers and it will work.

Mando and Charles love components!

10. Hide your caching

The BestsellerCell needs a lot of computation. Who bought what, when and how often? Why not cache the view?

According to the Rails docs, partials do that with the following pattern.

<% cache do %>
  Our bestsellers:
  <%= render :partial => "bestseller",
    :collection => Bestseller.find(:all) %>
<% end %>

Caching is exposed to the action. The action has to know about the partial’s caching requirements. This is wrong.

The partial computing and rendering the list knows best about its needs. So put the caching where it belongs – to the partial!

class BestsellerCell < Cell::Base
  cache :list, :expires_in => 10.minutes
 
  def list
    @bestseller = Bestseller.find(:all)
    render
  end
end

When calling

render_cell :bestseller, :list

nobody except the cell itself knows about the caching for that special page fragment. Even the expiry strategy is in the cell. This is called knowledge hiding.

More to come

The component-oriented approach with cells yields more improvements for your code. And there is more, yet. Interactive cells with AJAX often needed for rich client applications or dashboards – we got a cells-backed framework for that: Apotomo.

Go, try and love it.

Cells for Rails 3 considered stable!

Wednesday, September 29th, 2010

We finally pushed out the 3.4 gem of Cells, that’s view components for Rails.

Check out the github repo.

What’s Cells?

If you’re sick of partial+helper botching, if your views are getting too complex or you ever dreamed of rendering actions within actions, Cells is for you!

How can I get it?

Just run

$ gem install cells

to get the power of components and encapsulation into your Rails 3 app.

What’s new?

  • We lost about 50% of code compared to the 2.3 version.
  • Thanks to help of Yehuda Katz, who introduced the Rails 3 API to me in a hacking session, Cells are now real controllers!
  • Finally, view inheritance and nesting is documented ;-)

Go and check it out, you’ll love it! If you run into any trouble, don’t hesitate to bother us on #cells in irc.freenode.org! Keep it real!