Top Related Projects
View components for Ruby and Rails.
⚡ A Scope & Engine based, clean, powerful, customizable and sophisticated paginator for Ruby webapps
Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.
:tada: Makes http fun again!
Quick Overview
Cells is a view component framework for Ruby and Rails applications. It allows developers to encapsulate view logic into small, reusable components, promoting better organization and maintainability of view code. Cells can be used as an alternative to partials and helpers in Rails applications.
Pros
- Improves code organization and reusability by encapsulating view logic into components
- Enhances performance by caching at the component level
- Provides a clear separation of concerns between view components and controllers
- Supports various templating engines and testing frameworks
Cons
- Introduces a new concept and learning curve for developers familiar with traditional Rails views
- May add complexity to smaller projects where the benefits of componentization are less apparent
- Can lead to over-engineering if not used judiciously
- Limited adoption compared to standard Rails view practices
Code Examples
- Creating a basic Cell:
class UserCell < Cell::ViewModel
def show
render
end
private
def user_name
model.name
end
end
- Using a Cell in a view:
<%= cell(:user, @user) %>
- Caching a Cell:
class CommentCell < Cell::ViewModel
cache :show do
model.updated_at
end
def show
render
end
end
- Testing a Cell:
describe UserCell do
controller ActionController::Base
let(:user) { User.new(name: "John Doe") }
it "renders the user's name" do
html = cell(:user, user).call(:show)
expect(html).to have_content("John Doe")
end
end
Getting Started
To use Cells in your Rails application:
-
Add to your Gemfile:
gem 'cells' gem 'cells-rails' gem 'cells-erb'
-
Run
bundle install
-
Create a cell:
rails generate cell User show
-
Edit the cell in
app/cells/user_cell.rb
:class UserCell < Cell::ViewModel def show render end end
-
Create a view template in
app/cells/user/show.erb
:<div class="user"> <%= model.name %> </div>
-
Use the cell in your views:
<%= cell(:user, @user) %>
Competitor Comparisons
View components for Ruby and Rails.
Pros of cells
- More established and mature project with a larger user base
- Extensive documentation and community support
- Broader compatibility with various Ruby frameworks
Cons of cells
- Larger codebase, potentially more complex to understand and maintain
- May include features not needed for simpler projects
- Slightly higher memory footprint due to additional functionality
Code Comparison
cells:
class CommentCell < Cell::ViewModel
property :body
property :author
def show
render
end
end
cells>:
class CommentCell < Trailblazer::Cell
property :body
property :author
def show
render
end
end
The code structure is very similar between the two projects, with the main difference being the base class they inherit from. cells uses Cell::ViewModel
, while cells> uses Trailblazer::Cell
. This reflects the slightly different approaches and ecosystems of the two projects, but the core functionality remains largely the same.
Both projects aim to provide a view model solution for Ruby applications, with cells> being a more focused and streamlined version of the original cells project. The choice between them often depends on specific project requirements and personal preferences.
⚡ A Scope & Engine based, clean, powerful, customizable and sophisticated paginator for Ruby webapps
Pros of Kaminari
- Specialized for pagination, offering a more focused and optimized solution
- Seamless integration with various ORMs (ActiveRecord, Mongoid, etc.)
- Highly customizable with built-in view helpers and configuration options
Cons of Kaminari
- Limited to pagination functionality, less versatile for other view-related tasks
- May require additional gems for more complex view logic or components
Code Comparison
Kaminari (pagination):
@users = User.page(params[:page]).per(10)
<%= paginate @users %>
Cells (view components):
class UserCell < Cell::ViewModel
def show
render
end
end
<%= cell(:user, @user) %>
Summary
Kaminari excels in pagination, offering a streamlined solution with broad ORM support. Cells, on the other hand, provides a more general-purpose approach to view components, allowing for greater flexibility in structuring complex UIs. While Kaminari is ideal for projects primarily needing pagination, Cells offers a comprehensive solution for organizing and encapsulating view logic across various UI elements.
Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.
Pros of Simple Form
- More straightforward and easier to learn for beginners
- Extensive documentation and community support
- Seamless integration with Rails form helpers
Cons of Simple Form
- Less flexibility for complex, custom form layouts
- May introduce unnecessary overhead for simple forms
- Limited to form-specific functionality
Code Comparison
Simple Form:
<%= simple_form_for @user do |f| %>
<%= f.input :username %>
<%= f.input :email %>
<%= f.button :submit %>
<% end %>
Cells:
class UserForm < Cell::ViewModel
def show
render
end
end
# In view
<%= cell(UserForm, @user) %>
Key Differences
- Simple Form focuses on streamlining form creation within Rails views
- Cells provides a component-based approach for all UI elements, not just forms
- Simple Form is more opinionated about form structure, while Cells offers more flexibility
- Cells encourages better separation of concerns and reusability across the application
Use Cases
- Simple Form: Rapid development of standard forms in Rails applications
- Cells: Building complex, reusable UI components and improving overall application structure
Both libraries have their merits, and the choice depends on project requirements and team preferences.
:tada: Makes http fun again!
Pros of HTTParty
- Simple and intuitive API for making HTTP requests
- Supports various HTTP methods and automatic parsing of JSON responses
- Lightweight with minimal dependencies
Cons of HTTParty
- Limited to HTTP requests and responses
- Lacks advanced features for complex view rendering or component-based architecture
- Not designed for building reusable UI components
Code Comparison
HTTParty:
response = HTTParty.get('https://api.example.com/users')
puts response.body, response.code, response.message, response.headers.inspect
Cells:
class UserCell < Cell::ViewModel
def show
render
end
end
UserCell.new(model).call(:show)
Summary
HTTParty is a Ruby gem focused on simplifying HTTP requests and responses, making it easy to interact with web services and APIs. It excels in its simplicity and ease of use for HTTP-related tasks.
Cells, on the other hand, is a view component framework for Ruby applications, designed to create reusable UI components and improve the structure of complex views. It's more suited for building modular and maintainable user interfaces.
While both libraries serve different purposes, they can be complementary in a Ruby application: HTTParty for handling API requests and Cells for organizing the view layer.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Cells
View Components for Ruby and Rails.
Overview
Cells allow you to encapsulate parts of your UI into components into view models. View models, or cells, are simple ruby classes that can render templates.
Nevertheless, a cell gives you more than just a template renderer. They allow proper OOP, polymorphic builders, nesting, view inheritance, using Rails helpers, asset packaging to bundle JS, CSS or images, simple distribution via gems or Rails engines, encapsulated testing, caching, and integrate with Trailblazer.
Full Documentation
Cells is part of the Trailblazer framework. Full documentation is available on the project site.
Cells is completely decoupled from Rails. However, Rails-specific functionality is to be found here.
Rendering Cells
You can render cells anywhere and as many as you want, in views, controllers, composites, mailers, etc.
Rendering a cell in Rails ironically happens via a helper.
<%= cell(:comment, @comment) %>
This boils down to the following invocation, that can be used to render cells in any other Ruby environment.
CommentCell.(@comment).()
You can also pass the cell class in explicitly:
<%= cell(CommentCell, @comment) %>
In Rails you have the same helper API for views and controllers.
class DashboardController < ApplicationController
def dashboard
@comments = cell(:comment, collection: Comment.recent)
@traffic = cell(:report, TrafficReport.find(1)).()
end
Usually, you'd pass in one or more objects you want the cell to present. That can be an ActiveRecord model, a ROM instance or any kind of PORO you fancy.
Cell Class
A cell is a light-weight class with one or multiple methods that render views.
class CommentCell < Cell::ViewModel
property :body
property :author
def show
render
end
private
def author_link
link_to "#{author.email}", author
end
end
Here, show
is the only public method. By calling render
it will invoke rendering for the show
view.
Logicless Views
Views come packaged with the cell and can be ERB, Haml, or Slim.
<h3>New Comment</h3>
<%= body %>
By <%= author_link %>
The concept of "helpers" that get strangely copied from modules to the view does not exist in Cells anymore.
Methods called in the view are directly called on the cell instance. You're free to use loops and deciders in views, even instance variables are allowed, but Cells tries to push you gently towards method invocations to access data in the view.
File Structure
In Rails, cells are placed in app/cells
or app/concepts/
. Every cell has their own directory where it keeps views, assets and code.
app
âââ cells
â âââ comment_cell.rb
â âââ comment
â â âââ show.haml
â â âââ list.haml
The discussed show
view would reside in app/cells/comment/show.haml
. However, you can set any set of view paths you want.
Invocation Styles
In order to make a cell render, you have to call the rendering methods. While you could call the method directly, the preferred way is the call style.
cell(:comment, @song).() # calls CommentCell#show.
cell(:comment, @song).(:index) # calls CommentCell#index.
The call style respects caching.
Keep in mind that cell(..)
really gives you the cell object. In case you want to reuse the cell, need setup logic, etc. that's completely up to you.
Parameters
You can pass in as many parameters as you need. Per convention, this is a hash.
cell(:comment, @song, volume: 99, genre: "Jazz Fusion")
Options can be accessed via the @options
instance variable.
Naturally, you may also pass arbitrary options into the call itself. Those will be simple method arguments.
cell(:comment, @song).(:show, volume: 99)
Then, the show
method signature changes to def show(options)
.
Testing
A huge benefit from "all this encapsulation" is that you can easily write tests for your components. The API does not change and everything is exactly as it would be in production.
html = CommentCell.(@comment).()
Capybara.string(html).must_have_css "h3"
It is completely up to you how you test, whether it's RSpec, MiniTest or whatever. All the cell does is return HTML.
In Rails, there's support for TestUnit, MiniTest and RSpec available, along with Capybara integration.
Properties
The cell's model is available via the model
reader. You can have automatic readers to the model's fields by using ::property
.
class CommentCell < Cell::ViewModel
property :author # delegates to model.author
def author_link
link_to author.name, author
end
end
HTML Escaping
Cells per default does no HTML escaping, anywhere. Include Escaped
to make property readers return escaped strings.
class CommentCell < Cell::ViewModel
include Escaped
property :title
end
song.title #=> "<script>Dangerous</script>"
Comment::Cell.(song).title #=> <script>Dangerous</script>
Properties and escaping are documented here.
Installation
Cells runs with any framework.
gem "cells"
For Rails, please use the cells-rails gem. It supports Rails >= 4.0.
gem "cells-rails"
Lower versions of Rails will still run with Cells, but you will get in trouble with the helpers. (Note: we use Cells in production with Rails 3.2 and Haml and it works great.)
Various template engines are supported but need to be added to your Gemfile.
- cells-erb
- cells-hamlit We strongly recommend using Hamlit as a Haml replacement.
- cells-haml Make sure to bundle Haml 4.1:
gem "haml", github: "haml/haml", ref: "7c7c169"
. Usecells-hamlit
instead. - cells-slim
gem "cells-erb"
In Rails, this is all you need to do. In other environments, you need to include the respective module into your cells.
class CommentCell < Cell::ViewModel
include ::Cell::Erb # or Cell::Hamlit, or Cell::Haml, or Cell::Slim
end
Namespaces
Cells can be namespaced as well.
module Admin
class CommentCell < Cell::ViewModel
Invocation in Rails would happen as follows.
cell("admin/comment", @comment).()
Views will be searched in app/cells/admin/comment
per default.
Rails Helper API
Even in a non-Rails environment, Cells provides the Rails view API and allows using all Rails helpers.
You have to include all helper modules into your cell class. You can then use link_to
, simple_form_for
or whatever you feel like.
class CommentCell < Cell::ViewModel
include ActionView::Helpers::UrlHelper
include ActionView::Helpers::CaptureHelper
def author_link
content_tag :div, link_to(author.name, author)
end
As always, you can use helpers in cells and in views.
You might run into problems with wrong escaping or missing URL helpers. This is not Cells' fault but Rails suboptimal way of implementing and interfacing their helpers. Please open the actionview gem helper code and try figuring out the problem yourself before bombarding us with issues because helper xyz
doesn't work.
View Paths
In Rails, the view path is automatically set to app/cells/
or app/concepts/
. You can append or set view paths by using ::view_paths
. Of course, this works in any Ruby environment.
class CommentCell < Cell::ViewModel
self.view_paths = "lib/views"
end
Asset Packaging
Cells can easily ship with their own JavaScript, CSS and more and be part of Rails' asset pipeline. Bundling assets into a cell allows you to implement super encapsulated widgets that are stand-alone. Asset pipeline is documented here.
Render API
Unlike Rails, the #render
method only provides a handful of options you gotta learn.
def show
render
end
Without options, this will render the state name, e.g. show.erb
.
You can provide a view name manually. The following calls are identical.
render :index
render view: :index
If you need locals, pass them to #render
.
render locals: {style: "border: solid;"}
Layouts
Every view can be wrapped by a layout. Either pass it when rendering.
render layout: :default
Or configure it on the class-level.
class CommentCell < Cell::ViewModel
layout :default
The layout is treated as a view and will be searched in the same directories.
Nested Cells
Cells love to render. You can render as many views as you need in a cell state or view.
<%= render :index %>
The #render
method really just returns the rendered template string, allowing you all kind of modification.
def show
render + render(:additional)
end
You can even render other cells within a cell using the exact same API.
def about
cell(:profile, model.author).()
end
This works both in cell views and on the instance, in states.
View Inheritance
You can not only inherit code across cell classes, but also views. This is extremely helpful if you want to override parts of your UI, only. It's documented here.
Collections
In order to render collections, Cells comes with a shortcut.
comments = Comment.all #=> three comments.
cell(:comment, collection: comments).()
This will invoke cell(:comment, comment).()
three times and concatenate the rendered output automatically.
Learn more about collections here.
Builder
Builders allow instantiating different cell classes for different models and options. They introduce polymorphism into cells.
class CommentCell < Cell::ViewModel
include ::Cell::Builder
builds do |model, options|
case model
when Post; PostCell
when Comment; CommentCell
end
end
The #cell
helper takes care of instantiating the right cell class for you.
cell(:comment, Post.find(1)) #=> creates a PostCell.
Learn more about builders here.
Caching
For every cell class you can define caching per state. Without any configuration the cell will run and render the state once. In following invocations, the cached fragment is returned.
class CommentCell < Cell::ViewModel
cache :show
# ..
end
The ::cache
method will forward options to the caching engine.
cache :show, expires_in: 10.minutes
You can also compute your own cache key, use dynamic keys, cache tags, and conditionals using :if
. Caching is documented here and in chapter 8 of the Trailblazer book.
The Book
Cells is part of the Trailblazer project. Please buy my book to support the development and to learn all the cool stuff about Cells. The book discusses many use cases of Cells.
![](https://raw.githubusercontent.com/apotonick/trailblazer/master/doc/trb.jpg)- Basic view models, replacing helpers, and how to structure your view into cell components (chapter 2 and 4).
- Advanced Cells API (chapter 4 and 6).
- Testing Cells (chapter 4 and 6).
- Cells Pagination with AJAX (chapter 6).
- View Caching and Expiring (chapter 8).
The book picks up where the README leaves off. Go grab a copy and support us - it talks about object- and view design and covers all aspects of the API.
This is not Cells 3.x!
Temporary note: This is the README and API for Cells 4. Many things have improved. If you want to upgrade, follow this guide. When in trouble, join the Zulip channel.
LICENSE
Copyright (c) 2007-2020, Nick Sutterer
Copyright (c) 2007-2008, Solide ICT by Peter Bex and Bob Leers
Released under the MIT License.
Top Related Projects
View components for Ruby and Rails.
⚡ A Scope & Engine based, clean, powerful, customizable and sophisticated paginator for Ruby webapps
Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.
:tada: Makes http fun again!
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot