Posts Tagged Cells

Filters For Your Cells with cells-filters

Sunday, January 8th, 2012

There’s nothing like giving a quick update about Cells on a rainy sunday evening. Almost a year ago we were happy to introduce state-args into Cells. State-args help to prevent saving state in instance variables and instead pass variables from #render_cell as arguments, making your code more explicit.

One big problem was that filters couldn’t take advantage of that feature, thanks to a design flaw in Rails’ callback implementation.

Example?

Consider the following call to render a freaky bassist cell.

render_cell :bassist, :play, "C-sharp", "4/4"

The cell class wants to process the incoming data in a before_filter.

class BassistCell < Cell::Rails
  include Cell::Filters
 
  before_filter :prepare
 
  def prepare(state, tone, timing)
    @before = "In #{tone} and #{timing}"
  end

What now works with the new cells-filters gem is that filters (here, a before filter) can receive the state-args. The implementation is very simple using the hooks gem for easy peasy hooks and callbacks in Ruby.

However, we introduce a dependency to another gem, that’s why cells-filters was released as a separate gem. Go and try it! We might need to add some more behaviour to it, but please don’t ask me to completely bloat it.

You can still use the old-school filters from the Rails Callbacks module but you won’t be able to retrieve state-args. I don’t feel like fixing this in the Rails core itself as the implementation is a bit too complex for me.

Cells Development and a Roadmap.

Dudes, Cells is getting more and more of a standard in Rails development. In the last year, 2011, we had almost 90.000 downloads – this is awesome! Thank you so much.

We have more plans with Cells for 2012, here’s a short summary what we’re planning.

  • Get rid of the Rails dependency at all. We already got Cell::Base to use cells without a controller. Now we want to go one step further and make cells completely decoupled from Rails. Imagine cells (and, numerous “helper” gems like formtastic) being renderable in Sinatra or without a framework at all.
  • Use tilt as an alternative rendering engine. The Rails rendering layer is outdated and should use an abstracting rendering gem like tilt – until we can achieve this in the core, we will provide this in cells. That’ll make huge parts of cells completely independent from Rails.
  • Screencasts! Yeah, I’m working on a screencast series about cells, best practices and interesting solutions users sent in over the recent years.

Beside that, we’re permanently trying to incorporate the cells architecture into the Rails core. Let’s see where this will lead to in Rails 4.0. Happy new year, and… Cheers!

Mounting a Cell to a Route with Cells 3.8.

Wednesday, December 21st, 2011

Those of you having asked for mountable cells will be happy with the recent 3.8.0 release! We entirely removed the ActionController dependency. That essentially means you can have cells outside of the standard Rails stack. Cool, heh?

Cells 3.8.0 Released

Two little things in 3.8 changed. Cell::Base and Cell::Rails are now different classes with different semantics. Don’t panic – if you still derive your cells from Cell::Rails and use the #render_cell interface, only, nothing will change for you.

However, we had to tweak the API of some semi-public methods, here’s the new signatures.

Cell::Rails.create_cell_for(name, controller)
Cell::Rails.render_cell_for(name, state, controller, *args)

Well, nothing serious, it’s just the controller sliding to the end. If you use this anywhere, be sure to change it.

What’s new?

What is new is that Cell::Base is now decoupled from the ActionController. There simply is no AC-reference in Base anymore. However, this reference is still managed in Cell::Rails on purpose:

  • Calls to #url_for and friends automatically query the parent controller for host and action name. This makes it easy to embedd cells into a controller view and still having correct links in the cell.
  • Having the AC reference, people can still use request, params and session – if they need it. We strongly discourage accessing HTTP properties from a view component, though.

Let’s see what the new decoupled Base brings us.

Cells on Routes.

Deriving your cell from Base makes it routeable.

class PostsCell < Cell::Base
  def show
    @posts = Post.find(:all)
    render
  end

Routeable? Mountable? Well, let’s look at config/routes.rb to understand this.

match "/posts" => proc { |env|
  content = 
    Cell::Base.render_cell_for(:posts, :show)
  [ 200, {}, [ content ]]
}

How cool is that? You can mount a cell to a route without the ActionController overhead and still use the rendering, the caching and testing you all love from Cells. And, hey, it’s super super fast now.

The lack of the AC dependency makes cells even more versatile.

More on Routing

Since we got rid of the AC instance we have to take care of our URLs ourself. The cell still has access to all the URL helpers. Nevertheless, those helpers usually query the controller for host name portions, etc. That’s actually very simple with cells, too.

class PostsCell < Cell::Base
  def default_url_options
    {:host => "apotomo.de"}
  end

Just override the #default_url_options method as used from AC. This allows using the URL helpers as usual.

PostsCell.new.posts_url
#=> "http://apotomo.de/posts"

Let me know how these changes work for you! I’m eager to see new cases of applications in the next weeks.

Cells 3.7 released, taataa.

Thursday, October 13th, 2011

Is it a good sign when a minor release doesn’t yield any stunning new features? When there’s nothing breathtaking to talk about? I guess with Cells it is – the gem finally seems to get into what it should have been 6 years ago: a mature view components framework for Rails.

The 3.7 release, again, lost code – it’s goal was getting rid of the #options hang-over which succeeded. No more state in your cell, except if you choose to do so.

Here’s what changed.

Rails 3.x

Well, needless to say that 3.7 still runs with Rails 3.0 and 3.1. We were able to incorporate a couple of changes into Rails 3.1 to make Cells’ life even easier. Thanks, José for being such a patient maintainer and happy birthday to you ;-)

Caching Inheritance and Conditionals

Arthur Gunn brought us the :if option for caching. So, if you ever needed conditional caching in your cell, here it is.

class CommentsCell < Cell::Base
  cache :show, 
    :if => proc { |cell, opts| opts[:enable_cache] }

To pass in the required options, I’d use #render_cell.

render_cell(:comments, :show, :enable_cache => false)

See how easy it is to bypass (or enable) caching using :if? Also, don’t forget that the second block parameter is the options passed to #render_cell, which brings us to the next core change.

BTW, as a nice extension and in good OOP manners cpb made the cache configurations inheritable. A cell derived from CommentsCell will automatically inherit the cache setting for #show – no need for redundancy.

No more Options!

Luckily, we were able to remove the #options behaviour from Cells – it added unnecessary state, and we try to avoid internal state wherever possible (unlike the Rails core). Where you used to access the magic options hash in a state method you now use explicit state-args.

class CommentsCell < Cell::Base
  def show(user, comments)
    @user, @comments = user, comments
    render
  end

Since the method expects arguments (“state-args”), here’s how you’d pass them into.

render_cell(:comments, :show, user, @comments)

Any additional argument after the state name (2nd argument) is passed to the state. The rest is up to you.

If you want the old behaviour with the options hash that was “simply there”, just include the Deprecations module.

class CommentsCell < Cell::Base
  include Deprecations
 
  def show
    @user = options.first

Test your View Assigns

Another small addition is the #view_assigns method in Cell::TestCase. This works just like in conventional controller test (both Test::Unit and RSpec).

it "should assign correct values" do
  render_cell(:comments, :show)
  assert_equal @user_1, view_assigns[:user]

The view_assigns hash captures all instance variables that were assigned in the rendering cycle. Some people may like that – I don’t. However, here it is.

Have fun with Cells! ;-)

Rails Misapprehensions: Helpers are shit.

Wednesday, October 5th, 2011

When I started using Rails years ago I found helpers extremely cool. I could call a method in a view and it would help me by doing something. The method was simply there, no need to worry about its source and how to access it, just call it.

I got older, wiser, and more opinionated. I still like the concept of helpers – of methods. However, the way helpers are implemented in Rails sucks. Also, having object-disoriented functions in your view brings us back to the years where OOP still had to be invented.

In this post I’d like to discuss why I dislike Rails helpers and how to get out of that misery.

What’s a helper?

In Rails, a helper is a function.

<h2>
  Hello, <%= capitalize @user.name %>
</h2>

Here, the #capitalize method helps me capitalizing the username, which is freaking awesome. As this is pretty simple behaviour, let’s call helpers like this utility methods. They modify the input parameter, compute something or escape strings. Pretty straight-forward.

As a second example, I’d like to show a more complex helper.

<div id="sidebar">
  <%= render_news_for @user %>
</div>

This helper will iterate through news items for a particular user and render markup, maybe using several partials. Since it actively renders templates, let’s call this a view component.

Why are helpers shit?

At first sight, using helpers rocks. Capitalizing a string works like a charm – I simply call a function and it happens.

However, looking at the first helper I can identify several drawbacks.

module StringHelper
  def capitalize(string)
    string.capitalize
  end
  • Helpers in Rails are modules, which do not allow inheritance. If I’d need a foreign method I’d have to include another module into the helper module. Not a big deal.
  • Using the #capitalize methods happens without a receiver. The method is globally available in the view since Rails somehow mixes the helper into the view. So, what happens if I have two #capitalize methods in two different helpers mixed in the same view? I don’t have a clue. Do you?

Before getting to solutions, let me discuss another issue with helpers: Another real problem is the implementation in Rails – how these functions are made available to the view.

Helpers in Rails

Again, I’m not talking about how #form_for or #url_for are written internally, I’m talking about how these methods get into the view.

In Rails 3, all helpers are mixed into the view automatically, you still can insert additional modules using the controller’s helper facilities.

class HomeController < ApplicationController
  helper StringHelper

It’s not that the implementation as-it is bad code or something, it is the idea of magically mixing methods into the view instance to make them globally available. This adds complexity to the Rails core, namely around 280 LOCs. Just to mix some methods into the view.

Helpers are shit.

I desperately tried to demonstrate the major disadvantages of helpers in Rails. To summarize.

  1. I like utility methods. There is nothing wrong with having those little “helpers” in your view. What I don’t like is that they are called without an obvious receiver – they look and feel like functions. This is wrong.
  2. The way Rails mixes helpers into the view is error-prone and sucks. Following a slightly different approach there’s no need for all that complexity.
  3. Complex helpers suck. I do believe in view components and the need for those but they shouldn’t be rendering helper methods.

Moaning is fine, but let’s see how things could be changed.

Solution 1: Push Utility Methods into Decorators.

Luckily, a bunch of people feel uncomfy about the current helper architecture. My friend Steve Klabnik wrote a nice article about Jeff Casimir’s draper gem which introduces the Decorator pattern into Rails’ view layer.

Basically, the draper gem wraps existing model instances and provides utility (“helper”) methods on the decorated instance. Here’s an example.

class ArticleDecorator < ApplicationDecorator
  decorates :article
 
  def published_at
    model.published_at.strftime("%A, %B %e")
  end

Now that we defined the Decorator we can use it to wrap the actual model.

@article = ArticleDecorator.decorate(Article.find(1))

The wrapped model can then be used in the view.

<li>
  <%= @article.published_at %>
</li>

The interesting point is that we call the utility helper on the wrapped model which clearly states a receiver. No need for a homeless, global helper function. This way, we can have cleanly separated, domain-focused helpers for models. Decorators also allow inheritance and all other OOP features, since they are just objects.

Decorators are a solid technique when it comes to – well – decorating models. What can we do if there’s no matching model, for instance, when we need to call #url_for?

Solution 2: Use the Controller Instance as View Context

To learn more about that we should peek at the rendering cycle in Rails. What happens when a controller renders a template?

  1. An ActionView instance is created (this will be the “context”).
  2. The controller manages a magical module that contains all helper methods. This module is now mixed into the ActionView instance to make helpers available. I already discussed the need for hundreds of lines of code in order to achieve this “knowledge transfer” from the controller to the view.
  3. Next, instance variables from the controller are copied to the view instance as well.

These are 3 completely useless steps. Completely. Every template engine, whether it be Rails’ internal or tilt requires a so called view context whenever a template is rendered. Both instance variables and methods (that is, helper calls) used within the template are looked up on this view context instance.

Now, there is absolutely no reason for having a separate ActionView instance as view context! We can simply use the controller instance as context object and everything would work. No need to copy over variables, no need to transfer “helpers” to the view instance.

“Helpers” would be modules mixed into the controller – and that’s it.

class HomeController < ApplicationController
  include UrlMethods
 
  def show
    @link = link_to(home_url)

Notice how we can use the mixed-in “helper” methods in the controller instance – we simply included them.

<a href="<%= home_path %>">

The cool thing is we can also use the utility methods in the view which will be invoked on the controller instance, again. No magic copying, just modules.

The Cells project currently is experimenting with this approach and things work out fine. Will blog.

I can hear people now moan about too many mixed-in methods in their ActionController – and they are right! Again, this is due to Rails’ monolithic view/controller design. If one single controller is responsible for rendering an entire web page, then this controller has a lot of responsibilities – too many. That’s why we should use Cells to split up the view into components, which is discussed next.

Solution 3: Use View Components instead of Complex Helpers.

Helpers that compute data and render partials are scary. Often, there is too much concerns in the little helper.

def render_news_for(user)
  items = user.find_news
  render "shared/news", :items => items
end

Let’s assume the _news partial should be reusable throughout your application, needs some special helper function #sanitize and does caching.

<% cache do
  <%- for item in items %>
    <%= sanitize item.text %>
  <% end %>
<% end %>

Several problems here.

  • Every controller has to take care of requiring the special SanitizerHelper for the partial.
  • Caching happens by using helpers, again, which is no good .

Moving the partial and its behaviour into a cell would cleanly separate concerns. The cell could be used as view context and thus provide utility methods itself.

class NewsCell < Cell::Base
  cache :show
 
  def show(items)
    @items = items
    render
  end
 
  def sanitize(string)
    # ...
  end

This creates a reusable view component with a defined scope. Intentionally, I keep the cells discussion briefly as this would break the mold.

Combining Decorators and Cells

Using draper’s decorators within cells is what I figure a fantastic option. Where the decorator cleanly wraps the model object and provides utility methods for tweaking model data the cell separates the concern into a reusable view component, provides a limited scope and generic helper methods (like #url_for), and even caching!

I really don’t care whether draper, cells, or whatever replaces helpers – all I want is less magic code, more object-orientation and rock-solid software. This was a long post – gimme some feedback in the comments section or tweet me

Folks, here is the Cells Cheatsheet 1.0!

Thursday, September 15th, 2011

Why didn’t I do this earlier? Here’s the official Cells cheatsheet with all the information you need at hand when writing sweet view components in Rails.

It discusses the following topics.

  • Generator
  • Options processing
  • Rendering
  • Control Flow & Initialization
  • View Inheritance & Builders
  • Caching
  • Configuration
  • Test::Unit

There’s still some work to do and if something is missing feel free to fork and commit!

Enjoy your day!

Rails Misapprehensions: The Dependency Injection Pattern

Monday, August 15th, 2011

Inspired by the Stop hating Java post by my friend Andrzej I started to identify the pros and cons of a pattern called Dependency Injection in the Ruby/Rails world. Before I explain the pattern, let me discuss the problem – a dependency.

What is a Dependency?

Let’s say we’re working in a casual Rails controller instance. Whenever we access an object (or class) instance different to the current controller instance (i.e. self), we’re creating a dependency. Dependency here means the controller needs to know class and method names in another domain. Here are some typical dependencies found in many controller actions.

def show
  @comments = Comment.find(:all)

Here, the action knows both where and how to find the comments. It’s a dependency to the model layer.

def update
  # ...
  logger.notice "Comment #{@text} updated."

In this example, we have a strong dependency to the logger component – looking into the Rails code we can see that the #logger method in turn creates a logger instance, so we have to know about instantiation and usage of the logger.

%h1 Welcome, #{current_user.name}

This partial uses a helper method #current_user, which in turn queries controller and request in order to find the current user instance.

What’s the Problem with Dependencies?

Now, the examples above are code you’re gonna find in almost any Rails application – and there’s nothing wrong with that! However, problems might appear as soon as you want to test components separately.

For instance, what if I’d like to test my logging code within the controller, like asserting that the correct message is logged when something special happens?

it "logs correctly" do
  put :update
  assert_equal "Comment Yo! updated.", 
    @controller.logger.last_notice

I’d have to mock the logger instance to make it “testable”, here, to provide the #last_notice method.

Let’s say the original #logger method looks like this.

  def logger
    @logger ||= Rails::SmokeSignalLogger.new
  end

To mock the logger, people overwrite the respective method in the test case.

ActionController.class_eval do
  def logger
    @logger ||= Test::MockedLogger.new
  end

Code like this changes the logger for the entire test suite and might break other tests. A common solution is to reset the original method after each test. In other words, we change a global property for a local test – and this is wrong.

Another Problem: Configurability

In addition to the testing problems we get with dependencies, what if my colleagues love the way I program and plan to use one of my modules in their software (highly improbable). However, they don’t want the SmokeSignalLogger since they’re not speaking Indian, but they want to use another logging layer JungleDrumsLogger?

As soon as my component is imported in their application they’d probably monkey-patch my code to “configure” it.

NicksControllerMethods.class_eval do
  def logger
    @logger ||= 
      JungleDrumsLogger.new(:flavor => :coconut)
  end

I personally consider monkey-patching a code smell.

What’s a component?

Ok. I showed a couple of examples about dependencies and I used the word component a lot. The reason for this is: The Dependency Injection pattern is only applicable in software systems consisting of separated components. The idea is that outer components inject dependencies into smaller components.

A component as it might be a piece of software like a controller instance, an ActiveRecord row instance or a logger object. I see three attributes to make something a component.

  • First, a component has a limited scope of interest. It’s field of work is bounded to some special duty (logging messages, rendering a comments box, …).
  • Second, a component instance cannot access properties of other components, unless you’re providing a way to do so. For example, the logger may not access variables of the controller and vice-versa.

Dependency Injections in Rails

To get back to our examples, let’s see how we could apply DI to get rid of the logger dependency. Don’t let the controller create it itself, but do that on the outside and pass – “inject” – the object into the controller.

One flavor of DI is called Constructor Injection and would imply we inject the logger in the constructor.

class ActionController < ...
  def initialize(..., logger)
    @logger = logger
  end

Obviously, the outer framework would have to take care of creating and passing the logger.

  logger = BushDrumsLogger.new
  controller = ActionController.new(..., logger)

A second form is called Setter Injection where the controller exposes a writer for the injected attribute.

class ActionController < ...
  attr_writer :logger

Both the using frameworks or the test case can set the logger without overriding any code at all.

  controller.logger = TubeMailLogger.new

Cells and DI

One huge problem I see with Rails and DI is: currently, there are not enough components. We got one monolithic ActionController instance, a couple of row models and a global view instance – that’s it. This doesn’t make Rails a bad thing, or thousands of well-running apps out there!

However, the missing components in Rails make it hard to write reusable software and test these in isolation. That’s why we got the Cells gem – it provides reusable view components for Rails and goes perfectly together with DI.

Say we have a sidebar widget that displays the recent comments from your blog. A cell encapsulates that part of the page, the data aggregation and the rendering (read this post if you need a quick introduction to Cells).

Injecting the logger, ouch!

If we needed a special logging mechanism for the widget we could pass it into the component. I don’t know why a widget displaying comments would need to log, but let’s assume it.

%h1 My great blog
 
#sidebar
  = render_cell(:sidebar, :comments, logger)

The cell could then use the external logger without creating a dependency.

class SidebarCell < Cell::Base
  def comments(logger)
    logger.notice "Displaying comments at #{Time.now}!"
 
    render
  end

The additional arguments from the #render_cell invocation are directly passed as method arguments – this is what we call state-args in Cells.

It’s obvious that another project using that sidebar component could inject a completely different logger instance.

Testing with DI

The limited scope of a cell makes it pretty easy to test. Not only can we test that object-oriented “partial” in complete isolation but also can we pass in a mocked logger easily.

it "should render beautifully" do
  render_cell(:sidebar, :comments, mock_logger).
    should have_selector("ul")
end
 
it "should log correctly" do
  logger = ArrayLogger.new
  render_cell(:sidebar, :comments, logger)
 
  logger.last.should match /Logging/
end

No need to change or reset any global here, just throw-away instances and we’re done!

Conclusion

I can’t think of a cleaner solution for dissolving dependencies like these. The DI pattern makes it easy to keep your components dumb. The problem is that you first have to identify your dependencies, then refactor to components and inject instances from the controller (or wherever else).

Especially in Rails, Cells help to build a real MVC application with a data-aggregating ActionController (I call this FrontController) and fine-grained view components that get additional dependencies from the outside.

Cells 3.6.0 released – Rails 3.1 here we go!

Tuesday, June 14th, 2011

Just released Cells 3.6 – Cells are view components (aka portlets or widgets) for Rails. The new version runs with Rails 3.0 and 3.1 and it has no cool new features!

The view inheritance code got obsolete for 3.1 since Rails itself implements it, so Andrzej Krzywda and I decided to introduce a Strategy for separating different version portions in Cells. This makes it pretty easy to maintain two versions since the version-dependent code is abstracted into separate strategy files.

In the following version we will allow rendering specific template formats.

render :format => :js

This involves a slight refactoring of Rails’ internal rendering cycle and it’s highly probable that this fix will be merged into Rails 3.2 itself.

Now, go and have fun with Cells and Rails 3.1!

Rails Misapprehensions: Caching Views is Not the View’s Job!

Saturday, February 12th, 2011

Caching is a generic approach to speed up processing time in software. A common pattern used in Rails is to cache already rendered markup to save rendering time.

Basically, there are two concepts for view caching in Rails.

  • Page caching saves the complete page. This is good if your page doesn’t have dynamic parts.
  • Fragment caching which caches only parts of the page – usually, a more complex approach since you have to manage caching for multiple fragments.

Fragment caching

Rails supports fragment caching by letting you define cached parts in the view. You’d use the #cache method for that.

<% cache do %>
  All items in your cart:
  <%= render :partial => "items", 
    :collection => current_user.items %>
<% end %>

This works fine, fragments get rendered only if there’s a cache miss. Three problems with this approach.

  • You’re cluttering your views with caching declarations. It is handy to quickly define an area as cached, however, what if you suddenly change your cache key generation? You have to work through your views for a low-level task.
  • You shift responsibilities – the wrapping view defines the cached fragment. Instead of placing knowledge into the fragment, you aggregate all informations needed for caching on the outside.
  • Since you usually need to adjust the cache key for each fragment, you’re putting expiration logic into your views. This is definitely a no-go in MVC.

Let’s see how caching works in cells view components, which has a much simpler approach.

View caching in Cells

In cells there simply is no fragment caching. As cells are fragments caching happens on the class layer.

class CartCell < Cell::Rails
  cache :show
 
  def show(items)
    @items = items
    render
  end

In order to render the item list “fragment” you’d call #render_cell in your controller view.

  All items in your cart:
  <%= render_cell :cart, :show, current_user.items %>

Zero knowledge about caching in the view at all. Everything from cache key generation to actually marking fragments as cached happens inside the component, which knows best about its caching needs.

No fragment caching?

The first thing worth discussing here is: What if you want to cache a part of a cell, only? A fragment of a fragment, so to say.

You’d model this as another cell state. Period.

Let’s assume the item list in the cart should have a cache entry for each item.

class CartCell < Cell::Rails
  #cache :show
  cache :item do |cell, item|
    item.id
  end
 
  def item(item)
    @item = item
    render
  end
 
  def show(items)

Now, the cell’s show.erb view would call the #item state.

  You have <%= @items.size %> in your cart.
 
  <% @items.each do |item| %>
    <%= render({:state => :item}, item) %>

Again, the wrapping show state doesn’t know anything about the item view’s internal caching. Notice how we use render :state to invoke another cell state.

Using versioners

Ok, now, each item gets its very own cache entry. How does that work?

class CartCell < Cell::Rails
  cache :item do |cell, item|
    item.id
  end

Step-wise.

  • Every time the #item state is invoked the versioner block is called.
  • It receives the item instance (passed from render :state).
  • Now the versioner computes a cache key – the return value from the block is appended to the state’s generic cache key. In our example, we’d generate keys like cells/cart/item/1, and so on.

Next time the #item state is invoked with item no. “1” it won’t get rendered again since its cached view is returned instead.

Expiring caches

Expiring caches is one of the two real problems in computer science. The simplest approach is timed expiries.

class CartCell < Cell::Rails
  cache :item, :expires_in => 10.minutes do |cell, item|
    item.id
  end

Each item view gets flushed after 10 minutes. Things can be so simple.

Some people unlike me like sweepers. Cells ships with a sweeper method.

class ItemSweeper < ActionController::Caching::Sweeper
  observe Item
 
  def after_update(record)
    expire_cell_state CartCell, :item, record.id
  end

Just use expire_cell_state to swipe views item-wise from the cache. Thanks, Joe, for this example.

Even regular expression expiry works with expire_fragment! I didn’t even know this exists.

  expire_fragment %r(cells/cart/item/999)

This will remove items from item group 999, only – presuming these item ids start with 999.

Test your caching!

There are people telling you not to test your caching. These people either have bullet-proof integration tests, or are just lame. There is no excuse for missing caching tests.

I’d refactor the versioner to an instance method first, in order to unit-test.

class CartCell < Cell::Rails
  cache :item, :item_versioner
 
  def item_versioner(item)
    item.id
  end

Yeah, both blocks and methods work with cache. Let’s test that.

class CartCellCachingTest < Cell::TestCase
  test "item versioner appends id" do
    assert_equal "1", cell(:cart).item_versioner(@one)
  end

Testing if caching actually works is another good idea.

class CartCellCachingFunctionalTest < Cell::TestCase
  setup do
    ActionController::Base.perform_caching = true
    ActionController::Base.cache_store.clear
    @cell = cell(:cart)
  end
 
  teardown do
    ActionController::Base.perform_caching = false
  end

Enable caching and always clear the cache store – it’s good practice.

Testing cache writes

We should also check whether rendering a certain state alters the cache.

class CartCellCachingFunctionalTest < Cell::TestCase
  test "rendering item should write to cache" do
    expected_key = @cell.class.state_cache_key(:item, 1)
    assert_equal "cells/cart/item/1", expected_key

First, I assert we got correct keys.

    assert_not Cell::Base.cache_store.read(expected_key)
    render_cell(:cart, :item, @one)
    assert Cell::Base.cache_store.read(expected_key)
  end

Then I actually test if we got a cache write.

I agree that these tests are pretty much bound to the caching implementation in Cells and Rails. Also, I miss the ability to test cache reads and I’m waiting for inspiration from the community.

What could help writing real caching tests could be an #assert_caches or so. Let’s wait for reactions to this post.

Get OOP back to your views!

Ok, now we learned how simple Cells’ state caching is.

To sum things up: The previous examples have – at least – two cool advantages in comparison to fragment caching.

  • Although we cache fragments, we still have any caching knowledge in the class and not cluttered over the views itself.
  • Our “fragment” is an object-oriented component – you could inherit from the CartCell and override the view while keeping the caching mechanics. This is definitly something the Rails community – used to monolithic controllers – still has to discover and I absolutely agree that this is an evolving process.

However, I hope this post helps you when it comes to caching views. Don’t forget to check out the docs as well.

Cells 3.5 Release Party Summary

Sunday, February 6th, 2011

Yesterday we released Cells 3.5.0, which is another step towards real component-orientation in Rails. The release party was a big hit.

hairbolzheimer_rocknacht_iii_189

Cells is the one and only view components framework for Rails. It has a vivid growing community and had almost 10,000 downloads in the last year. That’s cool.

What’s new?

Basically we threw out a lot of code and deprecated some mechanics – we’re really happy to have abandoned the last ugly spots in Cells.

  • First of all, I introduced a CHANGES file which keeps growing. Keep that in sight if you wanna stay up-to-date about improvements and fixes.
  • The generator now uses the standard hooks for templates and tests.
  • States now receive arguments (aka state-args) to use less instance variables.
  • The rspec-cells gem finally runs and even has Capybara support.

The Generator

Thanks to the great work of Jorge Calás the cells generator now works like all the other generators in Rails 3. What has been the cells:cell generator is now simply cell.

It has hooks for templating and testing. Cells ships with generators for ERB and Haml views and Test-Unit and Rspec test cases.

$ rails g cell ShoppingCart display -e haml -t rspec
    create  app/cells/shopping_cart_cell.rb
    invoke  haml
    create    app/cells/shopping_cart/display.html.haml
    invoke  rspec
    create    spec/cells/shopping_cart_cell_spec.rb

Love it already.

State-args are the new options

You usually pass parameters into cells to model encapsulation.

render_cell :shopping_cart, :display, 
  :user => current_user, 
  :items => current_user.items

This drastically reduces coupling. The outer world (e.g. the controller) knows about dependencies whereas the cell should not care about retrieving its domain models.

In former versions, you accessed those arguments by querying the @opts instance variable. Ugh! Don’t do this anymore. The prefered way now is state-args.

class ShoppingCartCell < Cell::Base
  def display(args)
    @items = args[:items]

The options are passed as method arguments, and that’s what arguments were made for!

If you don’t like that, you can still use the #options method in your states.

  def display
    @items = options[:items]

This is for a soft transition, but be warned that Cells 4.0 will not store arguments in instance variables anymore. Don’t overuse instance variables – this typically is a smell of improper method chaining design.

States are helpers

Complex helpers typically invoke some code and then render a partial. This is exactly what render :state in cells does.

  - @items.each_with_index do |item, i|
    render({:state => :item_link}, item, i)

You typically do this in cell views. Notice how I pass arguments into the state.

class ShoppingCartCell < Cell::Base
  # ...
  def item_link(item, i)
    link_to item, item.url,
      :class => i.odd? ? :odd : :even

The #item_link state acts as a helper method, but as opposed to a plain helper you can use inheritance here and all the other benefits real object instances bring.

rspec-cells enhancements

If you like testing (you should love it!) you can use either traditional unit tests or RSpec. Include the rspec-cells gem into your Gemfile.

gem "rspec-cells"

The packaged generator will stub out a useful spec template for you.

$ rails g cell ShoppingCart display -t rspec

You can use webrat’s matchers, or even the new capybara string matchers, if you have capybara installed.

context "rendering display" do
  subject { render_cell(:shopping_cart, :display) }
 
  it { should have_selector("h1", :text => "The Cart") }
end

Get Cells!

We’re happy these improvements are on the road – tell us what you think about it! I’ll try to recover from the release party, now.

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!