Rails App

Phase Nine - User Experience

Now that we have fancy tricks to make awesome CSS, let’s take a look at the interface and update it a bit. While we can make our own, let’s use as much of the Twitter Bootstrap styles as we can.

Transcriptions Page

Right now the transcriptions are in a table with a cell for every property of the object. One way to make this easier to navigate would be to make each image the primary visual for the page in a grid. We can do this with some helpers Rails provides, as well as some styles that Bootstrap provides. Open app/views/transcriptions/index.html.erb. We want to update the file to first use Bootstrap’s layout options, specifically the idea of rows and columns.

<div class="row">
  <h1>Transcriptions</h1>

  <p>
    <%= link_to 'New Transcription', new_transcription_path, :class => "btn btn-large btn-primary" %>
  </p>
</div>

<% @transcriptions.in_groups_of(3) do |group| %>
<div class="row">
  <% group.compact.each do |transcription| %>
    <div class="col-xs-6 col-md-4">
      <div class="thumbnail">
        <%= link_to(image_tag(transcription.picture_url(:thumb)), transcription_path(transcription)) if transcription.picture.present? %>
        <div class="caption">
          <h3><%= transcription.title %></h3>
          <p><%= truncate(transcription.description, length: 250) %></p>
          <p>
            <%= link_to 'Edit', edit_transcription_path(transcription), :class => "btn btn-mini btn-primary" %>
            <%= link_to 'Destroy', transcription, method: :delete, data: { confirm: 'Are you sure?' }, :class => "btn btn-mini btn-danger" %>
          </p>
        </div>
      </div>
    </div>
  <% end %>
</div>
<% end %>

Before you start your server back up, what do you expect to happen? How should this be different? How many different helper methods are getting used here?

Show View

The transcription#show view needs some work too. We can make this look a lot better, separating the metadata (title and description) from the actual content (image and transcription). We can also update the notice (for when a new item has been created, or a current item has been updated). Open app/views/transcription/show.html.erb and replace with the following:

<% unless notice.nil? %>
<div class="row">
  <div class="col-md-12">
    <p id="notice" class="alert alert-info" role="alert">
      <button type="button" class="close" data-dismiss="alert">
        <span aria-hidden="true">&times;</span><span class="sr-only">Close</span>
      </button>
      <%= notice %>
    </p>
  </div>
</div>
<% end %>

<div class="row">
  <div class="col-md-12">
    <h1><%= @transcription.title %></h1>
    <h2>Description:</h2>
    <p>
      <%= @transcription.description %>
    </p>
  </div>
</div>

<div class="row">
  <div class="col-md-6">
    <h3>Picture</h3>
    <p>
      <%= image_tag(@transcription.picture_url, class: "img-responsive") if @transcription.picture.present? %>
    </p>
  </div>

  <div class="col-md-6">
    <h3>User name</h3>
    <%= @transcription.user_name %>
    <h3>Transcription</h3>
    <%= simple_format @transcription.transcription %>
  </div>
</div>

<div class="row">
  <%= link_to 'Edit', edit_transcription_path(@transcription), class: "btn btn-primary" %>
  <%= link_to 'Back', transcriptions_path, class: "btn btn-success" %>
</div>

Ok, hands off the keyboard. What is going on here? What is simple_format? What is the unless notice.nil? doing at the top? Why is there all that additional markup around the notice?

Forms

Let’s take a look at the form partial for transcriptions. Open app/views/transcriptions/_form.html.erb and make it read as follows:

<div class="row">
  <div class="col-md-12">
    <%= form_for(@transcription, :html => {:multipart => true}, :role => 'form') do |f| %>
      <% if @transcription.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@transcription.errors.count, "error") %> prohibited this transcription from being saved:</h2>

          <ul>
          <% @transcription.errors.full_messages.each do |message| %>
            <li class="alert alert-warning"><%= message %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <div class="form-group">
        <%= f.label :title %><br>
        <%= f.text_field :title, class: "form-control", placeholder: "Document Title" %>
      </div>

      <div class="field">
        <%= f.label :user_name %><br>
        <%= f.text_field :user_name, class: "form-control", placeholder: "User name" %>
      </div>

      <div class="form-group">
        <%= f.label :description %><br>
        <%= f.text_area :description, class: "form-control", placeholder: "Document Description" %>
      </div>
      <div class="form-group">
        <%= f.label :picture %><br>
        <%= f.file_field :picture %>
        <p class="help-block">Image for document.</p>
      </div>
      <div class="actions">
        <%= f.submit "Save", class: "btn btn-default" %>
      </div>
    <% end %>
  </div>
</div>

This code adds HTML 5 placeholders to the form fields. Anything else interesting going on here? Go back to your browser and add a new transcription, then edit it. Does this feel right?

You may notice that in the transcription#edit view, you never actually see the image, you can only ever upload a new image. We need a new view for this. For now, let’s make a new partial that will allow users to edit the title, description, but see the image that was uploaded to create a transcription.

Create a new file app/views/transcriptions/_edit_form.html.erb and add the following:

<%= form_for(@transcription, :html => {:multipart => true}, :role => 'form') do |f| %>
  <div class="row">
    <% if @transcription.errors.any? %>
      <div id="error_explanation">
        <h2><%= pluralize(@transcription.errors.count, "error") %> prohibited this transcription from being saved:</h2>

        <ul>
        <% @transcription.errors.full_messages.each do |message| %>
          <li class="alert alert-warning"><%= message %></li>
        <% end %>
        </ul>
      </div>
    <% end %>
  </div>

  <div class="row">
    <div class="form-group">
      <%= f.label :title %><br>
      <%= f.text_field :title, class: "form-control", placeholder: "Document Title", required: true %>
    </div>
    <div class="form-group">
      <%= f.label :description %><br>
      <%= f.text_area :description, class: "form-control", placeholder: "Document Description" %>
    </div>
  </div>

  <div class="row">
    <div class="col-md-6">
      <div class="form-group">
        <% if @transcription.picture.present? %>
          <%= image_tag(@transcription.picture_url, class: "img-responsive") %>
        <% else %>
          <%= f.label :picture %><br>
          <%= f.file_field :picture %>
        <% end %>
      </div>
    </div>
    <div class="col-md-6">
      <div class="form-group">
        <%= f.label :transcription %><br>
        <%= f.text_area :transcription, class: "form-control", placeholder: "Transcription", rows: 30 %>
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-md-6">
      <div class="actions">
        <%= f.submit "Save", class: "btn btn-default" %>
      </div>
    </div>
  </div>
<% end %>

If you look at the view code for transcriptions#new and transcriptions#edit, you’ll notice they both include the partial form.

<%= render 'form' %>

We need to update app/views/transcription/edit.html.erb to render the edit_form partial:

<%= render 'edit_form' %>

It’s time to explore your application a bit. Are there other things you could do to make the application easier to navigate?

Have you forgotten anything at this point? Starts with G, rhymes with hit

Summary

In this exercise, we implemented some basic styles that the Twitter Bootstrap framework provides. In many projects, the design process takes as much (if not more) time to get to a point where the front-end is thought through to ensure users can perform the intended actions of an application with little (or no) help from you, the developer. If you’re interested in this component of the software lifecycle, I would encourage you to consider taking a course in web development and design principles. Sometimes we even have them at HILT!