- Read Tutorial
- Watch Guide Video
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.
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:
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.
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.