Class Cell::Base
In: lib/cell.rb
Parent: Object

Basic overview

A Cell is the central notion of the cells plugin. A cell acts as a lightweight controller in the sense that it will assign variables and render a view. Cells can be rendered from other cells as well as from regular controllers and views (see ActionView::Base#render_cell and ControllerMethods#render_cell_to_string)

A render_cell() cycle

A typical render_cell state rendering cycle looks like this:

  render_cell :blog, :newest_article, {...}
  • an instance of the class BlogCell is created, and a hash containing arbitrary parameters is passed
  • the state method newest_article is executed and assigns instance variables to be used in the view
  • if the method returns a string, the cycle ends, rendering the string
  • otherwise, the corresponding state view is searched. Usually the cell will first look for a view template in app/cells/blog/newest_article.html. [erb|haml|...]
  • after the view has been found, it is rendered and returned

It is common to simply return nil in state methods to advice the cell to render the corresponding template.

Design Principles

A cell is a completely autonomous object and it should not know or have to know from what controller it is being rendered. For this reason, the controller‘s instance variables and params hash are not directly available from the cell or its views. This is not a bug, this is a feature! It means cells are truly reusable components which can be plugged in at any point in your application without having to think about what information is available at that point. When rendering a cell, you can explicitly pass variables to the cell in the extra opts argument hash, just like you would pass locals in partials. This hash is then available inside the cell as the @opts instance variable.

Directory hierarchy

To get started creating your own cells, you can simply create a new directory structure under your app directory called cells. Cells are ruby classes which end in the name Cell. So for example, if you have a cell which manages all user information, it would be called UserCell. A cell which manages a shopping cart could be called ShoppingCartCell.

The directory structure of this example would look like this:

  app/
    models/
      ..
    views/
      ..
    helpers/
      application_helper.rb
      product_helper.rb
      ..
    controllers/
      ..
    cells/
      shopping_cart_cell.rb
      shopping_cart/
        status.html.erb
        product_list.html.erb
        empty_prompt.html.erb
      user_cell.rb
      user/
        login.html.erb
    ..

The directory with the same name as the cell contains views for the cell‘s states. A state is an executed method along with a rendered view, resulting in content. This means that states are to cells as actions are to controllers, so each state has its own view. The use of partials is deprecated with cells, it is better to just render a different state on the same cell (which also works recursively).

Anyway, render :partial in a cell view will work, if the partial is contained in the cell‘s view directory.

As can be seen above, Cells also can make use of helpers. All Cells include ApplicationHelper by default, but you can add additional helpers as well with the Cell::Base.helper class method:

  class ShoppingCartCell < Cell::Base
    helper :product
    ...
  end

This will make the ProductHelper from app/helpers/product_helper.rb available from all state views from our ShoppingCartCell.

Cell inheritance

Unlike controllers, Cells can form a class hierarchy. When a cell class is inherited by another cell class, its states are inherited as regular methods are, but also its views are inherited. Whenever a view is looked up, the view finder first looks for a file in the directory belonging to the current cell class, but if this is not found in the application or any engine, the superclass’ directory is checked. This continues all the way up until it stops at Cell::Base.

For instance, when you have two cells:

  class MenuCell < Cell::Base
    def show
    end

    def edit
    end
  end

  class MainMenuCell < MenuCell
    .. # no need to redefine show/edit if they do the same!
  end

and the following directory structure in app/cells:

  app/cells/
    menu/
      show.html.erb
      edit.html.erb
    main_menu/
      show.html.erb

then when you call

  render_cell :main_menu, :show

the main menu specific show.html.erb (app/cells/main_menu/show.html.erb) is rendered, but when you call

  render_cell :main_menu, :edit

cells notices that the main menu does not have a specific view for the edit state, so it will render the view for the parent class, app/cells/menu/edit.html.erb

Gettext support

Cells support gettext, just name your views accordingly. It works exactly equivalent to controller views.

  cells/user/user_form.html.erb
  cells/user/user_form_de.html.erb

If gettext is set to DE_de, the latter view will be chosen.

Methods

Included Modules

ActionController::Helpers ActionController::RequestForgeryProtection

Attributes

controller  [RW] 
state_name  [RW] 

Public Class methods

Get the name of this cell‘s class as an underscored string, with _cell removed.

Example:

 UserCell.cell_name
 => "user"

Given a cell name, find the class that belongs to it.

Example: Cell::Base.class_from_cell_name(:user)

> UserCell

Creates a cell instance of the class nameCell, passing through opts.

Find the template for a cell‘s current state. It tries to find a template file with the name of the state under a subdirectory with the name of the cell under the app/cells directory. If this file cannot be found, it will try to call this method on the superclass. This way you only have to write a state template once when a more specific cell does not need to change anything in that view.

Declare a controller method as a helper. For example,

  helper_method :link_to
  def link_to(name, options) ... end

makes the link_to controller method available in the view.

The name suffix of a cell. Always ‘_cell’.

Return the default view for the given state on this cell subclass. This is a file with the name of the state under a directory with the name of the cell followed by a template extension.

Public Instance methods

Get the name of the current cell as a string.

Example:

 my_user_cell.class.name
 => "UserCell"
 my_user_cell.cell_name
 => "user"

Clone the instance variables on the current cell to an ActionView object.

Find the file that belongs to the state. This first tries the cell‘s view_for_state method and if that returns a true value, it will accept that value as a string and interpret it as a pathname for the view file. If it returns a falsy value, it will call the Cell‘s class method find_class_view_for_state to determine the file to check.

You can override the Cell::Base#view_for_state method for a particular cell if you wish to make it decide dynamically what file to render.

When passed a copy of the ActionView::Base class, it will mix in all helper classes for this cell in that class.

Defines the instance variables that Cell::Base#clone_ivars_to should not copy.

Access the current controller‘s params hash. This is only to be used in exceptional situations because it greatly increases coupling between the Cell and the Controller from which it is rendered.

Render the given state. You can pass the name as either a symbol or a string.

Render the given view file to a string. This will make the helpers defined using Cell::Base#helper available from that view and copy the instance variables from the Cell to the view.

Render the view belonging to the given state. This can be called from other states as well, when you need to render the same view file from two states.

Access the current controller‘s request object. This should only be used when you really need it.

Access the session

Empty method. Returns nil. You can override this method in individual cell classes if you want them to determine the view file dynamically.

If a view filename is returned here, we assume it really exists and don‘t invoke the superclass view finding chain.

[Validate]