After decades of struggling with myself, and after a fantastic RubyConf Australia with lots of love I finally managed to give cells users support for a global (brrr) #content_for helper.

Using It.

The new helper is added by including the cells-capture gem into your Gemfile.

gem 'cells-capture'

Cells need to declare explicitly that they want #content_for to access the global buffer by including Cell::Rails::Capture. This is meant to remind users that they’re kinda breaking their encapsulation (although it feels handy, I admit).

class BassistCell < Cell::Rails
  include Cell::Rails::Capture
 
  def show
    render
  end
end

You can now use the helper in your views – it will append passed content to the global buffer.

%div
  - content_for :javascripts
    $('#pick').append("Yo!")

Now What Is Your Problem?

We want cells users to have maximum comfortability, that is why the new helper is here. However, there are two problems with this approach.

  • You’re changing state of a global variable from a well-encapsulated cell.
  • A cached cell will mess up the global as you expect the cell to append something but it actually doesn’t (remember, there’s a cache hit).

Especially the latter is a problem: Imagine you’re rendering a page with a cached cell: the JavaScript of this component will be lost as the #content_for block is never called! This is a well-known problem in traditional Rails views where people call #content_for in a #cache block.

A Way Out?

A more explicit way of collection JavaScript from view components could help.

render_cell(:bassist, :play) do |cell|
  content_for(:global_js, cell.js)
end

Here, instead of calling #content_for in the cell’s view, you dedicate an additional method to it responsible for rendering the JavaScript (or any other content).

class BassistCell < Cell::Rails
  cache :play
 
  def play
    render # usually, content_for happens here.
  end
 
  def js
    render # this could be a JS template
  end
end

The content of the #js view will be added to the :global_js buffer. The cool thing: It will be invoked even when #play is cached!

Anyway, let us know how you use it and enjoy.

One Response to “Cells Got content_for Support.”

  1. Nick, thanks for following up on this issue, didn’t even think about calling content_for in the cell block.

Leave a Reply