Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
How do you render your blocks of code?

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
.bundle
app
lib
script
spec
testapp
.gitignore
.rspec
.rvmrc
Gemfile
Gemfile.lock
LICENSE
README.rdoc
Rakefile
blocks.gemspec

README.rdoc

Blocks

Wiki

Blocks is a replacement / complement to content_for with yield. It allows a user to specify a block capable of taking parameters that may be passed in when using that block. A user may also specify other blocks to be prepended or appended before or after a specific block is rendered. A template may also be specified to blocks that will provide the layout for a specific component and provide default implementations for its blocks. In this way, blocks is able to offer a very simple to use table generator (table_for) and list generator (list_for).

Installation

In Rails 3, add this to your Gemfile.

gem "blocks"

In Rails 2, add this to your environment.rb file. (At this time, it is untested in Rails 2)

config.gem "blocks"

Alternatively, you can install it as a plugin.

rails plugin install git://github.com/hunterae/blocks.git

Getting Started

At the very simplest level, blocks may be used in much the same way that content_for and yield are used:

To define a block:

<%= blocks.define :some_block_name, :some_parameter => 1, :some_parameter2 => 2 do |options| %>
  <%= options[:some_parameter] %>
  <%= options[:some_parameter2] %>
  <%= options[:some_parameter3] %>
<% end %>

Here, we are specifying two parameters that are provided automatically to the block named “some_block_name”. They are “some_parameter” and “some_parameter2”. In addition, the definition of the block is assuming that the user will be passing in another parameter called “some_parameter3”. However, all parameters are passed in in a hash, no error will occur if the user fails to specify “some_parameter3”.

Now, we may use the above block like follows:

<%= blocks.use :some_block_name %>

Here, we will see the output “1 2”. But if we pass in “some_parameter3”, as follows:

<%= blocks.use :some_block_name, :some_parameter3 => 3 %>

Then we will see “1 2 3”. Additionally, we can override any of the previous parameters when using a block simply by passing in the new value as a parameter:

<%= blocks.use :some_block_name, :some_parameter2 => "overridden", :some_parameter3 => 3 %>

In this case, we will see “1 overridden 3”. Thus, we now have content_for but with parameters.

Providing a Default Implementation of a Block

We can easily provide a default implementation of a block that will be used wherever it is specified unless that block has been specified elsewhere, in which case that version of the block will be rendered in it place. A perfect example of this would be by placing a default implementation of a block inside of a layout, and optionally specifying a different implementation to be rendered inside of your view. For example, inside one of my layouts (such as “views/layouts/application.html.erb”), I may provide my default page title:

<title>
  <%= blocks.use :title do %>
    My default page title
  <% end %>
</title>

Then, inside of a specific layout (such as “views/home/index.html.erb”), I may provide a specific page title for that particular view:

<%= blocks.define :title do %>
  A different page title
<% end %>

When the home index page is rendered, it's page title will be “A different page title” (assuming the HomeController uses the default application layout), but any other page that uses the default application layout will show “My default page title” as its page title. This occurs since the view is parsed first, so the definition of the block named “title” will already exist by the time the layout is rendered. However, for any page that does not specify a definition of the block “title”, the default implementation provided by the layout (using the command “blocks.use”) will be used.

What would happen, though, if no default implementation were provided? In other words, what if the code in the layout looked like this:

<title>
  <%= blocks.use :title %>
</title>

Well, in the case where the block if defined in the view (as was the case with “views/home/index.html.erb”), a title will be provided for the page. However, for any other page, since it can't find any implementation of the named block, it will simply return nothing, and you will have a page with no title.

Using partials

It's not completely accurate to say that if no block definition is found (as was the case above), “blocks.use :title” will simply return nothing. It will first try and render a partial with that name. By default, it will look for a partial named “_title.html.erb” in the “view/blocks” directory (or “_title.html.haml” if you're using haml). It will attempt to render that partial with all the options passed in as local variables to the partial.

Before and After Blocks

Blocks provides a very convenient way to specify blocks that are to be rendered before a specific block or after a specific block. For example:

<%= blocks.define :some_block do %>
  Some Block
<% end %>

<%= blocks.before :some_block do %>
  Before 1
<% end %>

<%= blocks.prepend :some_block do %>
  Before 2
<% end %>

<%= blocks.after :some_block do %>
  After 1
<% end %>

<%= blocks.append :some_block do %>
  After 2
<% end %>

Here, “blocks.before” is synonymous with “blocks.prepend” and “blocks.after” is synonymous with “blocks.append”. Now, if somewhere, we called:

<%= blocks.use :some_block %>

We would see: “Before 1 Before 2 Some Block After 1 After 2”.

What's particularly useful about this is that it doesn't matter if the “before” / “prepend” and “after” / “append” some before or after the “block.define” call. The only thing that matters is that the “blocks.define” occurs before the “blocks.use” call.

table_for

table_for is a useful example of using blocks in a very practical way. It is built entirely using the core blocks library. It is exposed as a helper method with the following prototype:

table_for(records, options={}, &block)

For example, if you have an Array of objects that respond to the following [:name, :email, :phonenumber] e.g.

@records = [OpenStruct.new({:name => "The Name", :email => "The Email", :phonenumber => "A phone number"}),
            OpenStruct.new({:name => "The Second Name", :email => "The Second Email", :phonenumber => "A second phone number"})]

And using table_for you define each column with the following:

<%= table_for @records do |table| %>
   <%= table.column :name %>
   <%= table.column :email %>
   <%= table.column :phonenumber %>
<% end %>

Will generate the following table:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Phonenumber</th>
    </tr>
  </thead>
  <tbody>
    <tr class="odd">
      <td>The Name</td>
      <td>The Email</td>
      <td>A phone number</td>
    </tr>
    <tr class="even">
      <td>The Second Name</td>
      <td>The Second Email</td>
      <td>A second phone number</td>
    </tr>
  </tbody>
</table>

Special Thanks

Thanks to Todd Fisher of Captico for implementation help and setup of gem and to Jon Phillips for suggestions and use case help.

Something went wrong with that request. Please try again.