Rails 5 : Blocks in View

Steps

Step 1

We want the task show page edit link to be displayed only for an admin. We want admin_area helper that takes a block like this:

<% admin_area do %>
  <%= link_to 'Edit', edit_task_path(@task) %> |
<% end %>

Here is the entire tasks/show.html.erb file:

<p>
  <strong>Name:</strong>
  <%= @task.name %>
</p>
<p>
  <strong>Complete:</strong>
  <%= @task.complete %>
</p>
<p>
    <%= @task.due_date %>
</p>
<% admin_area do %>
  <%= link_to 'Edit', edit_task_path(@task) %> |
<% end %>
<%= link_to 'Back', tasks_path %>

Step 2

Define admin_area helper in application_helper.rb:

def admin_area(&block)
  content_tag(:div, block.call, class: 'admin')
end

We need to generate a div tag that has admin class.

Step 3

Add show link to tasks index page.

<%= link_to 'Show', task %>

Here is the entire task index page.

<h1>Tasks</h1>
<table>
  <thead>
    <tr>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <% for task in @tasks %>
        <div class='task'>
            <strong> <%= task.name %> </strong>
        </div>
        <%= link_to 'Edit', edit_task_path(task) %>
        <%= link_to 'Show', task %>
      <% end %>
     </tr>       
  </tbody>
</table>

Step 4

Click on 'Show' link in the tasks index page. There is nothing that hides the Edit link. View page source. The generated html for the edit link does not have the div tag.

<a href="/tasks/10/edit">Edit</a> |
<a href="/tasks">Back</a>

Step 5

Change the view helper implementation:

def admin_area(&block)
  content_tag(:div, block.call, class: 'admin')
  nil
end

Step 6

Reload the task show page. View page source. The generated html is the same.

Step 7

From Rails docs:

The preferred method of outputting text in your views is to use the <%= “text” %> eRuby syntax. The regular puts and print methods do not operate as expected in an eRuby code block. If you absolutely must output text within a non-output code block (i.e., <% %>), you can use the concat method.

Change the implementation of application_helper.

def admin_area(&block)
  concat('foo', block.binding)
  yield
  concat('bar', block.binding)
end

Step 8

Reload the task show page. We get the error:

wrong number of arguments (given 2, expected 1)

Rails 5 has simplified the interface. Change the helper to:

def admin_area(&block)
  concat('foo')
  yield
  concat('bar')
end

Step 9

Reload the task show page. The browser displays:

foo  <a href="/tasks/10/edit">Edit</a> |
bar

View page source. You can see the foo and bar displayed before and after the edit link.

Step 10

Change the helper to wrap the edit link with the div tag with admin class.

def admin_area(&block)
  concat('<div class="admin">')
  yield
  concat('</div>')
end

Step 11

Reload the task show page. The browser displays:

<div class="admin"> Edit | </div> Back

We don't want to display the html string on the browser, we want the html be rendered by the browser.

Step 12

Use html_safe to force the string to be rendered on the browser:

def admin_area(&block)
  concat('<div class="admin">'.html_safe)
  yield
  concat('</div>'.html_safe)
end

View page source:

<div class="admin">  <a href="/tasks/10/edit">Edit</a> |
</div>

Now you can see the html in the page source.

Step 13

Add:

.admin {
    background: yellow;
}

to stylesheets/tasks.scss. The edit link will now be highlighted in yellow because of admin class.

Summary

In this article, you learned how to use blocks in view to simplify login the view by using your own view helpers.


Related Articles


Ace the Technical Interview

  • Easily find the gaps in your knowledge
  • Get customized lessons based on where you are
  • Take consistent action everyday
  • Builtin accountability to keep you on track
  • You will solve bigger problems over time
  • Get the job of your dreams

Take the 30 Day Coding Skills Challenge

Gain confidence to attend the interview

No spam ever. Unsubscribe anytime.