Jamie Gaskins

Ruby/Rails developer, coffee addict

Unordered List Helper for Rails

Published Mar 28, 2012

The Rails helper idea of "one HTML element per helper method" is a silly abstraction. I'm not sure it's the best idea for the general case. Here's an example:

<%= form_for @article do |f| %>
  <div class="field">
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :body %>
    <%= f.text_area :body %>
  </div>
  <%= f.submit %>
<% end %>

That includes a lot of boilerplate. All we care about is rendering a form that specifies 2 fields.

Reduce that boilerplate code

With the SimpleForm gem, we can reduce the code down to something like this:

<%= simple_form_for @article do |f| %>
  <%= f.input :title %>
  <%= f.input :body %>
  <%= f.submit %>
<% end %>

That's perfect! All of the labels are inserted automatically and the wrappers for the form inputs are handled through SimpleForm configuration with sensible defaults. In this form, we've reduced the boilerplate down to 2 lines (submit and form end tag) from 8.

Forms are definitely an area where there has always been a lot of unnecessary code, especially with the power of Rails helpers. I'd actually like to see this merged into Rails at some point, but SimpleForm has a lot of functionality and customization and merging every piece of it would be a bit much. However, we could easily optimize for the general case in Rails (wrapping the inputs in a div and inserting labels) very, very simply.

Now, where else can we do something like this?

Abstracting away any extra code that we don't need is always a huge win, but where else in Rails can we do such a thing?

Lists

Ordered and unordered lists are one of the biggest areas where we still write code the same way.

<ul>
  <% @items.each do |item| %>
    <li><%= item.name %></li>
  <% end %>
<ul>

Sure, that's not a lot of code, but how many times over the course of a project do you see this? If it's a project of any decent size, it'll be at least a dozen. Looping over each item within an array (or an ActiveRecord::Relation for people that care so much about precision ;-)) within the ul has always felt odd to me. I know it's required, but that doesn't make it sit well. It's just one of those things.

Awkward feelings aside, how much better would it feel if you could, instead, write this:

<%= unordered_list @items { |item| item.name } %>

Regardless of how you feel about the loop within the containing element, this presents more cleanly. We could also use other view helpers, say linking to each item:

<%= unordered_list @items { |item| link_to item.name, item } %>

There are other pieces of HTML that go together all the time. I'll update this article with more as I think of them.

UPDATE: I submitted this as a pull request to Rails, but it was rejected. I'd forgotten that you can already use content_tag_for to iterate over a collection, but I still wanted this abstraction at the list level. I still believe that the way we do one HTML tag per helper method is silly; it feels more like translating HTML into Ruby instead of abstracting away the HTML.

Every ul tag has as its children nothing but li tags. This means that writing li at all is solely to delimit the list items themselves and hence it becomes unnecessary boilerplate that can be abstracted away.

I very much disagree with them for rejecting this and I don't think the reason of "you can already do this by writing more code that's harder to read" is a good reason to reject it. :-) However, they are the core team and I'm sure they deal with indignant pull requests all the time, so I won't add to it.

TwitterGithubRss