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?
Ruby

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

What makes blocks particularly powerful is that it represent a combination of the ruby definition of blocks and partials. A block may be defined inline utilizing syntax similar to that of content_for:

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

or it may be written as a partial, existing in the controller view directory for whatever controller renders the view, or the globally configured blocks directory (views/blocks by default). The above block definition might then be written in the file views/blocks/_some_block_name.html.erb:

<%= some_parameter if defined?(some_parameter)%>
<%= some_parameter2 if defined?(some_parameter2) %>
<%= some_parameter3 if defined?(some_parameter3) %>

Notice that in the context of a partial, we have direct access to the parameters as local variables. However, since we're not utilizing “blocks.define” to create our block, we can't specify the default parameters :some_parameter and :some_parameter2 as we do in the first example. This has the potential to cause a runtime exception in the context of partials and we will need to assure that optional parameters are defined using “defined?”.

In the first example, we specified 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 (or local variables for partials), no error will occur if the user fails to specify “some_parameter3”.

Now, we may use the above block as follows:

<%= blocks.use :some_block_name %>

The system will first look for a block that's been defined inline by the name :some_block_name. If it cannot find one, it will try and render a partial with the same name within the current controller's view directory. Failing to find that, it will try and render a partial within the global blocks view directory (by default, views/blocks). If that partial also does not exist, it will give up and render nothing. (See [[Render Order]])

Here, we will see the output “1 2” for the first example (and “” for the second example). But if we pass in “some_parameter3”, as follows:

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

Then we will see “1 2 3” for the first example (and “3” for the second example). 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” for the first example (and “overridden 3” for the second example). Thus, we now have content_for but with parameters, and additional intelligence by utilizing partials.

table_for

table_for is a useful example of how blocks may be utilized in an invaluable 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 can very easily specify intricate details about the table (Note: most of the options in this example are optional):

<%= table_for @records, 
            :table_html => {:id => "records"}, 
            :header_html => {:style => "color:red"},
            :row_html => {:class => lambda { |parameters| cycle('odd', 'even')}},
            :column_html => {:style => "color:green"} do |table| %>
  <%= table.column :name, :column_html => {:style => "color:blue"}, :header_html => {:style => "color:orange"} %>
  <%= table.column :email %>
  <%= table.column :phonenumber, :column_html => {:style => "color:orange"}, :header_html => {:style => "color:blue"} %>
  <%= table.column :label => "???" do %>
    Some Random Column
  <% end %>
<% end %>

Will generate the following table:

<table id="records">
  <thead>
    <tr>
      <th style="color:orange">Name</th>    
      <th style="color:red">Email</th>    
      <th style="color:blue">Phonenumber</th>    
      <th style="color:red">???</th>
    </tr>
  </thead>
  <tbody>
    <tr class="odd">
      <td style="color:blue">The Name</td>    
      <td style="color:green">The Email</td>    
      <td style="color:orange">A phone number</td>    
      <td style="color:green">Some Random Column</td>
    </tr>
    <tr class="even">
      <td style="color:blue">The Second Name</td>    
      <td style="color:green">The Second Email</td>    
      <td style="color:orange">A second phone number</td>   
      <td style="color:green">Some Random Column</td>
    </tr>
  </tbody>
</table>

See table_for for details.

Building Layouts

Utilizing blocks, we can rethink the way we define our templates. Everywhere where we might be tempted to write “yield :some_block_name”, we can replace with “blocks.use :some_block_name”. This gives us the ability to provide a default implementation for that block if it cannot be found (see Providing a Default Implementation of a Block), and provides hooks for being able to render code before and after :some_block_name, utilizing “blocks.before :some_block_name” and “blocks.after :some_block_name” (See Before and After Blocks]).

See Building Layouts for more details on how to utilize Blocks to build layouts.

Wiki Docs

Questions or Problems?

If you have any issues with Blocks which you cannot find the solution to in the documentation, please add an issue on GitHub or fork the project and send a pull request.

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.