In the previous part of our Building a Ruby on Rails app series we completed the back end of our application, by fetching the book sales from Amazon.com. In this post we will look at the front end: showing the book list on the page together with their price movement.
The Controller
In the the first part of the series we created the Book model, that holds the book details Amazon supplied to us. Now we create the controller:
bundle exec rails g controller books index --skip-javascripts
This command generated the BooksController
with only one view index.html.erb. We only need to list the books, so the index view is sufficient. We also skip creating any JavaScript files that Rails would otherwise generate for us by default. Rails has generated a stylesheet file, books.scss, which we'll use later to style the page.
Let's now update the routes:
# config/routes.rb
resources :books, :only => :index
It's important that we limit the routes generated by resources
method, so they match our real views.
Our controller will show a list of books and also a date of when the book sales when were last updated:
# app/controllers/books_controller.rb
class BooksController < ::ApplicationController
def index
@books = Book.order(:last_sales_rank)
@rank_updated = BookSale.last_updated
end
end
The last_updated
method could look like this:
# app/models/book_sales.rb
class BookSale < ActiveRecord::Base
belongs_to :book
def self.last_updated
last.created_at.strftime('%d %B %Y')
end
end
The View
The view needs to have a list and a placeholder for the updated date:
<div class="app-content-main">
<ul class="books">
<% @books.each do |book| %>
<li class="book">
<div class="sale col">
<div class="cf">
<div class="rank">
<%= book.last_sales_rank %>
<span class="pr"><%= book.previous_sales_rank %></span>
</div>
<%= movement_class book %>
</div>
</div>
<div class="img col">
<%= image_tag book.image_url, alt: book.title %>
</div>
<div class="col det">
<h3><%= book.title.html_safe %></h3>
<p class="details">
<span><%= book.author %></span>
<span><%= book.published_at.strftime('%d %B %Y') %></span>
</p>
</div>
</li>
<% end %>
</ul>
<div class="updated">
Last updated <%= @rank_updated %>
</div>
</div>
We navigate through books and show their image, title, author, and publication date. We also show their previous and current sales ranks, and an arrow, whose direction indicates the sales movement:
# app/helpers/books_helper.rb
module BooksHelper
def movement_class(book)
class_name = 'none'
title = 'No movement'
movement = book.sales_rank_movement || 0
if movement > 0
class_name = 'down'
title = 'Sales rank is going down'
end
if movement < 0
class_name = 'up'
title = 'Sales rank is going up'
end
class_name = "move move-#{class_name}"
content_tag :i, '', class: class_name, title: title
end
end
This method is simple, it looks at the sales_rank_movement
we added to the book in the previous part, and generates the corresponding markup.
Let's now style the arrow and other parts of the page.
The CSS
We add the styles to the books.scss file that Rails generated for us:
.app-content-main {
width: 650px;
background: #fff;
padding: 1em 0;
border-radius: 3px;
float: left;
}
.books {
.book {
position: relative;
padding-left: 90px;
min-height: 90px;
display: table-row;
}
.col {
display: table-cell;
padding: 1.5em .5em;
vertical-align: top;
border-bottom: 1px solid #f2f5f8;
&.sale {
vertical-align: middle;
position: relative;
padding-right: 1em;
padding-left: 1.5em;
text-align: right;
}
&.det {
padding-right: 2.5em;
}
}
.book:last-child .col {
border-bottom: none;
}
.img {
width: 70px;
img {
max-width: 100%;
}
}
.rank {
display: block;
color: #999;
margin-right: 1em;
line-height: 1.05;
text-align: right;
.pr {
color: #bbb;
font-size: .9em;
display: block;
}
}
.move {
position: absolute;
right: .5em;
top: 50%;
margin-top: -6px;
&.move-none {
width: 15px;
height: 3px;
background: #ECC70D;
}
&.move-down {
border-top: 8px solid #f99;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
}
&.move-up {
border-bottom: 8px solid #98DA8E;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
}
}
h3 {
font-size: 1.15em;
margin-bottom: .3em;
line-height: 1.1;
color: #333;
}
.details {
font-size: .9em;
color: #999;
span {
display: inline-block;
margin-right: 1em;
}
}
}
The arrows are created by using borders as explained in our caret generator.
Conclusion
In this part of Building a Ruby on Rails app series, we showed the list of books with their details and visual cues of their sales rank movement. At the bottom of the page we showed the date, when the sales ranks were last fetched from Amazon.com.
This complete our series. You can check out the previous posts in this series below: