Skip to content

From Cells 3 to Cells 4 Upgrading Guide

Bart ten Brinke edited this page Jun 25, 2015 · 7 revisions

3.x to 4.0

Template engine

You have to pick and install one (or multiple) template engines for your application. This will usually end in adding gem "cells-haml" to your Gemfile. Learn more.

Architecture

The old dialect Cell::Base and Cell::Rails got superceded by Cell::ViewModel. So, every cell should start like

class SongCell < Cell::ViewModel
  def show
    render
  end

This also changes a few semantical things in your cell.

render_cell helper

The helper #render_cell got replaced with #cell.

cell(:song, Song.find(1), genre: "Heavy Metal")

The first argument is a model to present, then a hash with additional parameters can be passed. It will return the cell instance. In a view, this will automatically call #to_s, which internally invokes the #show method.

Multiple public methods

Often, people use one cell class with multiple public methods to render different views. If you don't want to render the #show method use #call.

cell(:song, Song.find(1)).(:details)

Of course, this assumes you have a method #details.

class SongCell < Cell::ViewModel
  def details
    render
  end

Options

Passing options used to work like this.

render_cell(:comment, @comment, layout: :fancy)

This still works with #cell.

cell(:comment, @comment, layout: :fancy)

However, those options are now available via #options.

def show
  @layout = options[:layout]

  render 
end

You can also do that in the initializer.

def initialize(model, options)
  @layout = options[:layout]
  super
end

Don't you forget to call super here!

You can still pass options to the method directly, this works as follows.

cell(:comment, @comment).call(:show, layout: :fancy)

Your action method will then need to process those options.

def show(layout=default)
  render layout: layout
end

The second parameter to cell is available via #model.

Builders

Builders are no longer executed in the controller context. They also now receive the exact args list that was passed into #cell.

If you need controller data for your builders, push that into the options hash.

class SongCell < Cell::ViewModel
  build do |model, options|
    HitCell if model.is_a? Hit
  end

Asset Pipeline

The old configuration in application.rb looks like this.

config.cells.with_assets = ["comment"] # references Comment::Cell.

This becomes a fully qualified underscore constant name.

config.cells.with_assets = ["comment/cell"] # references Comment::Cell.

Also, assets like comment.js do no longer have their own directory but all sit in the cell's views directory.

Migrating from Cells 3 to Cells 4 with Rails help

As the migration from Cells 3 to Cells 4 can be quite big, you might want to have an intermediate step along the way. The code snippets below will allow you to update to the Cells 4 gem while keeping the Cell 3 DSL and all your controller methods/helper calls in your cell views. This way you can upgrade to the Cells 4 gem and then rewrite your cells one a the time. We do this by creating a new cell that acts as the bridge between the old style and the new style. Your own cells should inherit from ApplicationCell to make the magic happen.

class ApplicationCell < Cell::ViewModel
  # Include all the application helper methods and 
  include ApplicationHelper
  
  # You need to include controller methods you where using from Rails explicitly.
  include AbstractController::Helpers
  include AbstractController::Translation
  # Look at https://github.com/rails/rails/tree/4-2-3/actionpack/lib/abstract_controller
  # if you need more.

  # If you want to access controller methods from your cell, you can hook that up like this
  delegate :current_user, :controller_name, :flash, to: :parent_controller
  helper_method :current_user
  helper_method :controller_name
  helper_method :flash
  
  # Cells 4 no longer uses action_name. 
  # This workaround sets it whenever a state is called.
  attr_accessor :action_name

  def call(state=:show, *args)
    @action_name = state
    super
  end
end

As the render_cell method was removed in Cells 4, we will place it back in our ApplicationHelper. This throws a deprecation warning, so you should be able to pick out old render_cell calls quite easily.

module ApplicationHelper
  # Cells 3 style cell render call.
  def render_cell(name, state, *args)
    cell(name).(state, *args)
  end

  deprecate :render_cell
end