Fetching contributors…
Cannot retrieve contributors at this time
101 lines (81 sloc) 3.93 KB

Stories in Ready


How do you render your blocks of code?

With blocks, you can:

  1. Easily define named blocks of view-level code, capable of taking parameters as arguments

  2. Render a defined block of view-level code and pass in an arbitrary number of parameters

  3. Provide a default block of code to render if a named block is not found

  4. Specify view-level code to render before, after, or around a particular block of code

  5. Render a collection of elements using a defined block

Author's Note

To fully appreciate how powerful Blocks can be, i highly recommend checking out the project TableFor first. This is a gem that was built using Blocks and WithTemplate (an extension of Blocks) with very few lines of code, and illustrates the power of Blocks and WithTemplate and how they can be can be used to build extremely useful reusable UI components.


In Rails 3 or Rails 4, add this to your Gemfile.

gem "blocks"

Simple Case

<% blocks.define :sample do |a, b| %>
  This is a snippet of code with parameters <%= a %> and <%= b %> passed in<br>
<% end %>

<% blocks.before :sample do %>
  This is a snippet of code that will render before the block named :sample<br>
<% end %>

<% blocks.after :sample do %>
  This is a snippet of code that will render after the block named :sample<br>
<% end %>

<%# This is when the code gets rendered %>
<%= blocks.render :sample, "1", 2 %>

<%# Provide a wrapper element to wrap around the rendered block
<%= blocks.render :sample, "1", 2, :wrap_with => {:tag => :div, :id => "sample" } %>

<%# Rendering a block that doesn't exist will simply render nothing %>
<%= blocks.render :sample2 %>

<%# Rendering a block that doesn't exist with a default definition will simply use the default definition %>
<%= blocks.render :sample3 do %>
  This is a snippet that will get rendered if a block named :sample3 is not defined anywhere
<% end %>

A More Complicated Case

In this example, @brands will represent a collection of brands fetched from the database

<% blocks.define :brand do |brand| %>
  Brand <%= %>
<% end %>

<%= blocks.render :brand,
                  :collection => @brands,
                  :wrap_with => { :tag => :ul, :id => "brands", :style => "list-style-type:circle" },
                  :wrap_each => { :tag => :li,
                                  :id => {|brand| "brand#{}"}, 
                                  :class => { cycle("even", "odd") },
                                  :style => "padding-left: 20px;" }%>

A Practical example

Surround your javascript includes and css includes in your template with a named block, and from the view, the included order can easily be changed. Note: I use this approach in every single project I setup.

In layout, such as application.html.erb:

<!DOCTYPE html>
    <%= blocks.render :stylesheets do %>
      <%= stylesheet_link_tag "application", :media => "all" %>
    <% end %>
    <%= blocks.render :javascripts do %>
      <%= javascript_include_tag "application" %>
    <% end %>

In a view, stylesheets and javascript files can easily be prepended, appended, or replace the existing set of includes:

<% blocks.before :stylesheets do %>
  <%= stylesheet_link_tag "SOME_STYLESHEET_TO_INCLUDE_FIRST", :media => "all" %>
<% end %>
<% blocks.after :stylesheets do %>
  <%= stylesheet_link_tag "SOME_STYLESHEET_TO_INCLUDE_LAST", :media => "all" %>
<% end %>

<%# Flat out replaces the javascript includes %>
<% blocks.define :javascripts do %>
  <%= stylesheet_link_tag "MY_JAVASCRIPT_FILES_TO_INCLUDE", :media => "all" %>
<% end %>