Posts Tagged Cells

Using Rails Gems Like simple_form in Sinatra Or Anywhere

Monday, June 25th, 2012

Rails comes with a massive amount of helpful gems. Those gems are part of Rails’ success and they make Rails the most versatile framework in the Ruby world.

No longer shall using those gems be limited to a Rails environment! The new Cells 3.8.5 allows using many gems in any project, from simple scripts to Sinatra applications, without the Rails dependency. Beside actionpack, no other Rails gem is required.

Let’s see how the great gem simple_form can be used in a Ruby script.

The Gemfile.

For demonstration purpose I want to pass a real ActiveRecord model to simple_form. That is why the Gemfile might look bloated at first sight.

source :gemcutter
 
gem "cells" , "~> 3.8.5"
gem "sqlite3"
gem "activerecord"
gem "simple_form"

The New Module.

If you’re not familiar with Cells yet, check this post. The cell we’re writing is pretty straight-forward with two new lines.

1
2
3
4
5
6
7
8
9
10
11
12
13
require 'cell/base'
require "cell/rails/helper_api"
require "simple_form"
 
class MusicianCell < Cell::Base
  include Cell::Rails::HelperAPI
 
  self._helpers = RoutingHelpers
 
  def show
    @musician = Musician.find(:first)
  end
end

First, note that we use Cell::Base to derive from since we don’t want the Rails dependency (line 5). We then include the module necessary to provide the helpers outside of Rails (line 6).

How Does URLs Work?

Most gems rely on routing helpers. For instance, simple_form is using polymorphic routes helpers like musician_path to compute URLs. Naturally, outside of Rails we don’t have those routes and need to provide them ourselves. This is what happens in line 8.

8
  self._helpers = RoutingHelpers

The corresponding RoutingHelpers module now is up to you.

module RoutingHelpers
  def musician_path(model, *args)
    "/musicians/#{model.id}"
  end
end

Using simple_form In The View.

The state view sitting at musician/play.html.erb might use simple_form now. And, hey, you are not limited to ERB. Cells comes with all the template engines that Rails supports. Use HAML if you fancy. Use Slim to loose weight. Or Whatever.

<%= simple_form_for @musician do |f| %>
  <%= f.input :name %>
  <%= f.button :submit %>
<% end %>

See how easy that is?

The Ruby Script.

Now using all that is as simple as any other steps. This example is just a Ruby script – note that the following code could also be in a Sinatra action, a Webmachine resource, a mailer or whatever you prefer.

require 'musician_cell'
 
MusicianCell.append_view_path(".")
puts Cell::Base.render_cell_for(:musician, :play)

This is enough to render the form with simple_form.

<form accept-charset="UTF-8" action="/musicians/1" class="simple_form edit_musician" id="edit_musician_1" method="post">
  <div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="_method" type="hidden" value="put" /></div>
	<div class="input string optional"><label class="string optional" for="musician_name">Name</label><input class="string optional" id="musician_title" maxlength="255" name="musician[title]" size="50" type="text" value="Steve" /></div>
	<input class="button" name="commit" type="submit" value="Update Musician" />
</form>

Cool, isn’t it?

Using Cells Caching.

If you want to use Cells caching you just have to provide a cache store. You may use any ActiveSupport compatible cache store here, no limits!

cache = ActiveSupport::Cache::MemoryStore.new
 
Cell::Base.render_cell_for(:musician, :play) do |c|
  c.cache_configured = true
  c.cache_store = cache
end

See how we use dependency injection now to configure the cell? This makes the whole workflow completely encapsulated and clean. We might provide some utility methods in the near future to make this setup a little bit more convenient. Let me know what you need. Shap!

Maximum Modularity with Cells and Rails Engines

Wednesday, March 7th, 2012

Do you remember when we were writing a reusable sidebar element some time ago? The sidebar used in many controllers was implemented using a cell which encapsulated both assets and code in one place. Those were good times.

When needed, we could render the box with a render_cell call anywhere in our app.

#sidebar
  = render_cell :posts, :recent

Reusability With Engines

Now, imagine this sidebar box was so universally usable that you wanna use it in another project. Code is usually distributed with gems in a Ruby environment – but how does that work with partials, helpers, view code?

We got engines in Rails. We got Cells. We got gems. So let’s pack the cell in an engine gem!

Engines were designed to distribute controllers, views and models between Rails projects. As an example, lots of the authorization gems around use engines for reusable login pages or password reset forms that can be used right in your project. There was no easy way for reusing partials and behaviour, though, unless you’re using cells.

The Cell, Gemified.

In order to ship the sidebar posts box I first need to create a Rails engine.

$ rails plugin new sidebar --mountable

This creates a distributable directory with all the files needed to mount it into a Rails app.

As a second step we need to move the PostsCell into that gem.

$ mv app/cells/posts sidebar/app/cells/

You can now include the sidebar gem in any application using the Gemfile.

gem 'sidebar', :path => 'vendor/plugins/sidebar'

To render your reusable component, just use the render_cell call as you did in the originating application.

Conclusion

Damn, this conclusion came fast, but there is really not more to say. Oh, did I mention that you should update to Cells 3.8.3 for full engines support in Rails 3.0, 3.1 and even 3.2?!

Cells + Engines bring real reusability to Rails. It’s da shit.

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.