Creating a Custom View Helper in Rails
In this guide we're going to build a Rails view helper method to dynamically add labels to records based on their status.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this guide we're going to build a Rails view helper method to dynamically add labels to records based on their status.

Technically we could build this type of functionality into the view, however that's considered a poor practice. Instead we can build a view helper method that will generate the HTML code for us dynamically.

To begin, open the index.html.erb and _post.html.erb files. In index.html.erb we are going to create another table heading and call it Status.

<!-- app/views/posts/index.html.erb -->

<h1>Posts</h1>

<table class="table table-striped table-hover">
  <thead>
    <tr>
      <th>
        #
      </th>
      <th>
        Date
      </th>
      <th>
        User
      </th>
      <th>
        Rationale
      </th>
      <th>
        Status
      </th>
      <th></th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <%= render @posts %>
  </tbody>
</table>

And in _post.html.erb, we are going to create another column for the status element.

<!-- app/views/posts/_post.html.erb -->

<tr>
  <td>
    <%= post.id %>
  </td>
  <td>
    <%= post.date %>
  </td>
  <td>
    <%= post.user.full_name %>
  </td>
  <td>
    <%= truncate(post.rationale) %>
  </td>
  <td>
    <%= post.status %>
  </td>
  <td>
    <%= link_to 'Edit', edit_post_path(post), id: "edit_#{post.id}" %>
  </td>
  <td>
    <%= link_to 'Delete', post_path(post), method: :delete, id: "delete_post_#{post.id}_from_index", data: { confirm: 'Are you sure?' } %>
  </td>
</tr>

If you hit refresh in the browser, you will now be able to see the new status.

large

Though it looks nice, I think a color would make it even better. We can do that by leveraging the label class provided by bootstrap.

The code for adding color is:

<!-- app/views/posts/_post.html.erb -->

<td>
  <span class='label label-primary'><%= post.status %></span>
</td>

This is how it looks on the browser:

large

This looks nice, but we're not done yet! If you see, all the status messages have the same color. However a good UI/UX should give users the ability to quickly see which posts are approved, rejected, etc. And using different colors is a great way to accomplish this.

To implement this, we are going to create our own helper method in posts_helper.rb.

# app/helpers/posts_helper.rb

module PostsHelper
  def status_label status
    case status
    when 'submitted'
      content_tag(:span, status.titleize, class: 'label label-primary')
    when 'approved'
      content_tag(:span, status.titleize, class: 'label label-success')
    when 'rejected'
      content_tag(:span, status.titleize, class: 'label label-danger')
    end
  end
end

Here, we are creating a method called status_label that is taking the status value as an argument. We are using a case statement here because it's cleaner to read compared to an if-else conditional (in this case). Each case statement returns a span value using a method called content_tag. This method creates HTML code for us and you can send a number of arguments to it. The first argument is span which is the type of HTML element we want to generate. The default is div, so we have to say it explicitly when we want a span class to be generated. The second value is the status, which is the parameter we're calling. And the third is a class for the CSS label color. As you've probably guessed, each label name stands for a different color.

We're also calling the titleize method on the status so it capitalizes the first letter of each status. Without calling this method the statuses would all be in lower case.

Now, if you refresh the browser you'll see the label colors are changing dynamically.

large

The last task we'll perform in this guide is refactor the view helper code. I'm going to move the code to a private method called status_span_generator. A rule of thumb in Ruby is to have method names that reflect its functionality. Earlier, we had a method called status_label, but it was generating HTML code. So, let's make the change.

# app/helpers/posts_helper.rb

module PostsHelper
  def status_label status
    status_span_generator status
  end

  private

    def status_span_generator status
      case status
      when 'submitted'
        content_tag(:span, status.titleize, class: 'label label-primary')
      when 'approved'
        content_tag(:span, status.titleize, class: 'label label-success')
      when 'rejected'
        content_tag(:span, status.titleize, class: 'label label-danger')
      end
    end
end

I like the way this code looks, and if you refresh the browser you'll see that everything is still working properly.

Resources