Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Arjan van der Gaag http://agwebdesign.nl

« Newer Snippets
Older Snippets »
Showing 1-3 of 3 total  RSS 

Helper for quicly creating standard tables

I often want to display an array of objects as a table on a page, and I end up doing the the same things over and over again. I wrote this helper method to speed things up:

def table(collection, headers, options = {}, &proc)
  options.reverse_merge!({
    :placeholder  => 'Nothing to display',
    :caption      => nil,
    :summary      => nil,
    :footer       => ''
  })
  placeholder_unless collection.any?, options[:placeholder] do
    summary = options[:summary] || "A list of #{collection.first.class.to_s.pluralize}"
    output = "<table summary=\"#{summary}\">\n"
    output << content_tag('caption', options[:caption]) if options[:caption]
    output << "\t<caption>#{options[:caption]}</caption>\n" if options[:caption]
    output << content_tag('thead', content_tag('tr', headers.collect { |h| "\n\t" + content_tag('th', h) }))
    output << "<tfoot><tr>" + content_tag('th', options[:footer], :colspan => headers.size) + "</tr></tfoot>\n" if options[:footer]
    output << "<tbody>\n"
    concat(output, proc.binding)
    collection.each do |row|
      proc.call(row, cycle('odd', 'even'))
    end
    concat("</tbody>\n</table>\n", proc.binding)
  end
end


Writing...

<% table(@posts, %w{ID title}) do |post, klass| -%>
    <tr class="<%= klass %>">
      <td><%= post.id</td>
      <td><%= post.title </td>
    </tr>
<% end -%>


results in...

<table summary="A list of posts">
  <thead>
    <tr>
      <th>ID</th>
      <th>Title</th>
    </tr>
  </thead>
  <tfoot><tr><td colspan="2"></td></tr></tfoot>
  <tbody>
    <tr>
      <td>1</td>
      <td>My first post</td>
    </tr>
  </tbody>
</table>


Or, when the collection is an empty array (collection.any? returns false), a placeholder message is displayed:

<p class="placeholder">Nothing to display</p>


So you pass in your collection and an array of strings as your table headers as the first two arguments, and the third is a hash of options you can use to set the contents of the table's summary-attribute, the caption and footer-elements and the placeholder.

The summary attribute defaults to "A list of [objects]", where 'objects' is derived from the class name of the collection.

The function finally takes a block for every element in the collection, yeilding it the element and either 'odd' or 'even' so you can use CSS-classes to apply a zebra stripes effect.

Helpful extensions to core Ruby classes

If you find yourself doing this a lot:

<% if @collection.any? -%>
<ol>
  <% for item in @collection %>
    <li><%= item %></li>
  <% end -%>
</ol>
<% end -%>


...you might want to extend two Ruby core classes to automagically print out HTML-lists. Extend Array with:

def to_html_list(type = :ol)
  self.inject("<#{type}>\n") { |output, item| output << "\t<li>#{item}</li>\n" } << "</#{type}>\n" if self.any?
end


Now you can produce both OL (default) and UL lists. You can easily convert a Hash into a DL-list by extending it like so:

def to_html_list
  self.inject("<dl>\n") { |o, p| o << "\t<dt>#{p[0]}</dt>\n\t<dd>#{p[1]}</dd>\n" } << "</dl>\n" if self.any?
end


Extending core classes is a bit dangerous but I use these in almost every Rails project.

Helpers for placeholder messages

When there are no results to display for a user you often want to tell so using a placeholder message, such as 'Sorry, no posts matched your criteria' or 'You have no recent purchases'.

I created these two helpers to make using placeholder a little bit easier.

def placeholder(message = 'Nothing to display', options = {}, &proc)
  # set default options
  o = { :class => 'placeholder', :tag => 'p' }.merge(options)

  # wrap the results of the supplied block, or
  # just print out the message
  if proc
    t = o.delete(:tag)
    concat tag(t, o, true), proc.binding
    yield
    concat "</#{t}>", proc.binding
  else
    content_tag o.delete(:tag), message, o
  end
end
  
def placeholder_unless(condition, *args, &proc)
  condition ? proc.call : concat(placeholder(args), proc.binding)
end


Now you can use it as follows:

<%= placeholder :message => 'Nothing found' %>

<% placeholder do %>
Nothing found.
<% end %>


Results in:

<p class="placeholder">Nothing found</p>


The second function allows the following usage:

<% placeholder_unless @posts.any?, 'No posts found' do %>
  <%= render :partial => @post %>
<% end %>


The point is it all results in a nice, painless message with consistent markup and styling and I find it makes my code a bit more readable.

I'm sure the code could be optimized but for now it works.
« Newer Snippets
Older Snippets »
Showing 1-3 of 3 total  RSS