Rails Girls KL 2017 Travel Guide App Tutorial

Based on the original Rails Girls app guide by Vesa Vänskä, @vesan
Extended for Rails Girls KL 2017 (@railsgirlskl) by Ei-Vonne Kwan, @evkwan
Contributors: Faezrah, @fzrhrs

Get to know the tools

 

Web browser

 

CodeAnywhere

1.Creating the application

We're going to create a new Rails application, and it's going to be a travel catalogue app. In this app, you will be able to create posts about travel destinations and even add a picture to each destination.

Hope you have already followed the quick setup guide for CodeAnywhere. Open your new railsgirls workspace in CodeAnywhere.

At the start of the workstation, your terminal should be in the workspace directory location. Double check by typing this command in the terminal commandd line:

$ pwd 

Don't type the $ character. The $ character is a cue that you should enter the command in the terminal.

You should see:

Now, let's create our first Rails app:

$ rails new rgtravelguide 

When you run this command, it will install all the necessary files and folders for your first Rails application. Note it may take some time to finish the installation.

Once it's done, you need to go to your newly created Rails app by typing:

$ cd rgtravelguide 

You can then start the rails server by running:

$ rails server -b 0.0.0.0 

Notice now in the terminal, the command prompt is not visible. The command prompt looks like this:

This is because you are now in the Rails server in that terminal tab.

When the command prompt is not visible you cannot execute new commands. If you try running cd or another command it will not work. To return to the normal command prompt, hit CTRL + C in the terminal to quit the server.

If you want to run other commands, simply open another terminal tab by right-clicking on your container and then selecting the SSH Terminal option.

Tip: You can keep two terminal tabs open. One for running the server and other to run all the commands.

Mentor: Explain what each command does. What was generated? What does the server do?

Preview your new by clicking on the preview link that was shown in your workspace container info page, as shown below:

Notice your URL should look something like this: https://rgtravelguide-evkwan154533.codeanyapp.com . If you have accidentally shut your container info page, you can access it again by right clicking on your container, and select the "Info" option as shown below:


Checkpoint: Your default Rails app page should look like this:

Once you clicked on the preview link you should see "Welcome aboard" page, which means that the generation of your new app worked correctly.

2.Create Travel Guide scaffold

We're going to use Rails' scaffold functionality to generate a starting point that allows us to list, add, remove, edit, and view things; in our case travel destinations.

Mentor: What is Rails scaffolding? (Explain the command, the model name and related database table, naming conventions, attributes and types, etc.) What are migrations and why do you need them?

Exit your server if it is still running on the terminal on in the run tab and type in the code below in the terminal:

$ rails generate scaffold destination name:string image:string title:string post:text 

The scaffold creates new files in your project directory, but to get it to work properly we need to run a couple of other commands to update our database and restart the server.

$ rake db:migrate
$ rails server -b 0.0.0.0

Then preview in the browser, you should append /destinations to the URL shown in the address bar of your browser.

You should see an empty page with the title "Listing destinations". At the bottom you will see a link to add a "New Destination".

Play around with this a little. We got all these when we ran those scaffold commands earlier.

Checkpoint: Your listing destination page should look something like this:

3.Design

Mentor: Talk about the relationship between HTML and Rails. What part of views is HTML and what is Embedded Ruby (ERB)? What is MVC and how does this relate to it? (Models and controllers are responsible for generating the HTML views.)

The app doesn't look very nice yet. Let's do something about that. We'll use Bootstrap to give us nicer styling real easily.

In Codeanywhere, on the left side navigation panel, right-click on your rgtravelguide container and select "Refresh" as below:

A list of files should now appear (we generated them using the rails command in previous section).

Use the file browser to open rgtravelguide/apps/views/layouts/application.html.erb.

Below the line:

<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>

Add:

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

Then replace:

<%= yield %>

With:

<div class="container">
  <%= yield %>
</div>

Let's also add a navigation bar and footer to the layout. In the same file, right under <body> add:

<nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <%= link_to "RGTravelGuide", destinations_path, class: "navbar-brand" %>
    </div>
    <div id="navbar" class="navbar-collapse collapse">
      <ul class="nav navbar-nav">
        <li><%= link_to "Destinations", destinations_path %></li>
      </ul>
    </div>
  </div>
</nav>

And before </body> add:

<footer class="footer">
  <div class="container">
    <p class="text-muted">Rails Girls KL 2017</p>
  </div>
</footer>

Don't forget to save your work everytime you make changes.

Now let's also change the styling of the destinations table. Open app/assets/stylesheets/application.css and at the bottom add:

body { padding-top: 50px; }
footer { margin-top: 100px; }
table, td, th { vertical-align: middle; border: none; }
th { border-bottom: 1px solid #DDD; }

Finally, delete the file app/assets/stylesheets/scaffolds.scss because we don't really need the default style generated by Rails.

Now make sure you saved your files and refresh the browser tab previewing your app to see what was changed. You can also change the HTML & CSS further.

Mentor: Talk a little about CSS and layouts.

4.Refine the navigation

Considering "destination" is the most important object in your app, we are going to put the "Add Destination" button on the navigation bar to make it always available.

Open app/views/layouts/application.html.erb, under the line:

<li><%= link_to "Destinations", destinations_path %></li>

Add:

<li><%= link_to 'Add New Destination', new_destination_path %></li>

5.Adding picture uploads

We need to install a piece of software to let us upload files in Rails.

Open Gemfile in the project directory using your text editor and under the line

gem 'sdoc', '~> 0.4.0', group: :doc

Add:

gem 'carrierwave'

Mentor: Explain what libraries are and why they are useful. Describe what open source software is.

Hit CTRL + C in the terminal to quit the server.

In the terminal run:

$ bundle install 

Now we can generate the code for handling uploads. In the terminal run:

$ rails generate uploader Image 

At this point you need to restart the Rails server process in the terminal.

Note: Some people might be using a second terminal to run the rails server continuously. If so you need to restart the Rails server process now. This is needed for the app to load the added library.

Go to the terminal tab which runs the server and then hit CTRL + C to quit the server. Once it has stopped, you can press the up arrow to get to the last command entered, then hit enter to start the server again.

Open app/models/destination.rb and under the line:

class Destination < ActiveRecord::Base

Add:

mount_uploader :image, ImageUploader

Open app/views/destinations/_form.html.erb and change:

<%= f.text_field :image %>

To:

<%= f.file_field :image %>

Sometimes, you might get an TypeError: can't cast ActionDispatch::Http::UploadedFile to string.

If this happens, in file app/views/destinations/_form.html.erb change the line:

<%= form_for(destination) do |f| %>

To:

<%= form_for @destination, html: { multipart: true } do |f| %>

In your browser, again click on the New Destination link. This time we can actually add a new destination post. When you upload an image though it doesn't look nice because it only shows a path to the file, so let's fix that.

Open app/views/destinations/show.html.erb and change:

<%= @destination.image %>

To:

<%= image_tag(@destination.image_url, :width => 600) if @destination.image.present? %>

Now refresh your browser to see what changed.

Mentor: Talk a little about HTML.

6.Design the destination post upload form

Now that you have an upload form that works, let's make it look nice with the help of Bootstrap.

Open app/views/destinations/_form.html.erb, where you see:

<div class="field">

Change to:

<div class="form-group">

And add a form-control CSS class into each form input

<%= f.text_field :name, class:'form-control' %>
<%= f.file_field :image, class:'form-control' %>
<%= f.text_field :title, class:'form-control'%>
<%= f.text_area :post, class:'form-control'%>

To make the button look nice, add a btn btn-primary CSS class to it, like so:

<%= f.submit class:'btn btn-primary' %>

We also want to justify the position of the Create button, so that it appears in the middle of the page. Add two css classes, row text-center to the parent div of the button, as shown below:

  <div class="actions row text-center">
    <%= f.submit class: 'btn btn-primary'%>
  </div>

Refresh your page to see what has changed.

To give more editing space in the text area where we would write a post about our destination, add a row number into the text area element as below:

<%= f.text_area :post, rows: "10", class:'form-control'%>

Checkpoint: My destinations upload form looks like this:

Now it's time to make the Destinations gallery (destination list) look more professional. For that, we are going to replace the table layout with a div layout.

Mentor: Talk a little about table vs div (semantic markup).

Open app/views/destinations/index.html.erb and replace all lines with:

<p id="notice"><%= notice %></p>

<h1 class="row text-center">Destinations</h1>
</br>
<% if @destinations.any? %>
  <% @destinations.in_groups_of(3) do |group| %>
    <div class="row">
      <% group.compact.each do |destination| %>
        <div class="col-xs-4" style="margin-top: 20px;">
          <div class="panel panel-default">
            <div class="panel-body">
              <%= link_to image_tag(destination.image_url, :width => '100%', :height => '200px'), destination if destination.image.present?%>
            </div>
            <div class="panel-footer">
              <h4 class="text-center"><%= link_to destination.name, destination %></h4>
              <p class="text-center"><%= destination.title %></p>
            </div>
          </div>
        </div>
      <% end %>
    </div>
  <% end %>
<% else  %>
   <p>No destinations found.</p>
<% end %>

Mentor: Explain what the new code means line by line, and talk a little about Bootstrap 12 grids layout.

Refresh it! We get a neat looking destinations gallery. Click the "New Destination" button, and add more destinations with real text - the page will look much better with content. There is a principle of contemporary web design: content is the best decoration.

8.Design the Destination details page

Click the title of a photo, and you will be brought to the details page of the destination. Now it is still scaffold generated by Rails, so let's make it better.

Open app/views/destinations/show.html.erb and replace all lines with

<p id="notice"><%= notice %></p>

<div class="row" style="margin:auto; width: 60%">
<h1 class=" text-center" style="margin-bottom: 30px;" >
  <strong><%= @destination.name %></strong>
</h1>

<p class="text-center">
  <%= image_tag(@destination.image_url, :width => 600) if @destination.image.present? %>
</p>

<h2 class="text-center">
  <strong><%= @destination.title %></strong>
</h2>

<p style="white-space: pre-line;">
  <%= @destination.post %>
</p>

<br/>

<p class="text-center">
  <%= link_to 'Edit', edit_destination_path(@destination) %> |
  <%= link_to 'Delete', @destination, confirm: 'Are you sure?', method: :delete %> |
  <%= link_to 'Back', destinations_path %>
</p>
</div>

Quick notes on what we have just done: we have removed the field labels such as "Name", "Image", "Title", "Post" from the page, as we really only want the values of these fields. They become the content to our page, and visitors do not need the labels to understand the content.

Mentor: Explain what the new code means line by line. Explain briefly about field-value pairs relating to models.

9.Finetune the routes

If go to the index page of your app (that's your app URL without /destination part) it still shows the "Welcome aboard" page. Let's make it go directly to the destinations page.

Open config/routes.rb and after the first line add

root "destinations#index"

Test the change by refreshing the preview page in your browser.

Mentor: Talk about routes, and include details on the order of routes and their relation to static files.

10.Create static page in your app

Lets add a static page to our app that will hold information about the author of this application — you!

$ rails generate controller pages about

This command will create you a new folder under app/views called /pages and under that a file called about.html.erb which will be your info page. Tip: Do not forget to right-click on your root project folder and refresh in order to see the newly generated files.

get "pages/about"

It also adds a new simple route to your routes.rb.

Now you can open the file app/views/pages/about.html.erb and add information about you in HTML and append /pages/about to the URL to see your new about page.

To add a link to the info page, open the file app/views/layouts/application.html.erb, and insert:

<p class="navbar-text navbar-right">
  <%= link_to 'About', pages_about_path, class:'navbar-link' %>
</p>

In between:

  <%= link_to "RGTravelGuide", destinations_path, class: "navbar-brand" %>
</div>
And:
<div id="navbar" class="navbar-collapse collapse">

What the inserted code does is that it is adding a new menu item for the info page which will be placed to the right of the navigation bar. Restart your server if you haven't already, and refresh your page to check it out!

11.What's Next?

Enhance your travel guide app. Some sugesstions:

Check out our guides!