BUILDING A SCAFFOLD - Learn Ruby on Rails For Web Development (2015)

Learn Ruby on Rails For Web Development (2015)

Chapter 5. BUILDING A SCAFFOLD

We're getting down to the meat and potatoes of our app now. In this chapter we're going to start to build out the main functionality for our site.

Let's break down that functionality...

Since we're building a Pinterest clone, we're going to want to be able to upload a 'pin' that consists of an image, and a written description. We'll need to store that information in our database and show that information on the website.

Rails (of course) has something that will take care of all of that for us, and it's called a scaffold. A Rails scaffold creates a model, a migration, controllers to handle everything, and views to see and manipulate things.

To create a scaffold, we just need to issue one simple command:



1 $ rails g scaffold pins description:string
2

We've seen a similar command when we set up Devise. 'rails g' stands for 'rails generate', so this command is telling Rails to generate a scaffold named 'pins'.

We can name our scaffold anything, but sticking with our pinterest theme, we'll name ours 'pins'. We could just as easily have named it horses, or tweets, or posts. The convention is to name it something plural (ending in an s).

The command ends with 'description:string'. That tells Rails to create a column in our database called description, and to give that description a string data type.

When dealing with database stuff, you will generally work with either strings (which is a short string of characters or text), integers (whole numbers), decimals (decimal numbers), or maybe text (longer text like paragraphs). Possible data types include:

:binary

:boolean

:date

:datetime

:decimal

:float

:integer

:primary_key

:references

:string

:text

:time

:timestamp

We don't really need to know what all of those are right now, you can do a little research in the future as you grow as a Rails developer.

The 'rails g scaffold' command creates a migration, and like all migrations we'll need to rake our database to push the migration up to the database:



1 $ rake db:migrate
2

And later when we push these changes up to Heroku, we'll need to run Heroku's rake db:migrate command:



1 $ heroku run rake db:migrate
2

When you ran the 'rails g scaffold' command, you probably noticed that the command line outputted a bunch of things that Rails just created for you. You'll notice that there's a new folder in your views directory called /pins/.

Before we look through those files, we need to restart our server and check out our website because something strange has happened.

Head over to https://pinterested-codemy.c9.io (or whatever your URL is)


(https://pinterested-codemy.c9.io - After Scaffold)

Reload the page. Notice anything different? Everything should look a little 'off'. The font is a slightly different size, the buttons look just a little different, and everything seems...somehow wrong.

What happened? Whenever we generate a scaffold in Rails, one of the files that gets created is a CSS file for the scaffold! That CSS file is over-writing our Bootstrap CSS file (the one we created and named bootstraply.css.scss).

So take a look at the /app/assets/stylesheets directory and you should see the new stylesheet, named: /app/assets/stylesheets/scaffolds.css.scss

If you want, you can open that file and just take a look at it for fun, but what we need to do is simply delete it. You can do that by putting your mouse over the file name right there on the directory tree on the left-hand side of your development environment, right-clicking, and selecting "Delete".

Now if we head back to our website and hit reload, the site should look the way it did earlier under Bootstrap.

CHECKING OUT THE SCAFFOLD VIEWS

The 'rails g scaffold' command that we ran created a bunch of files for us, so let's take a look at all of them now by running our trusty rake routes command:



1 $ rake routes
2

At the top of the list you should see a bunch of routes marked 'pins'. Pay special attention to the GET routes as those are generally the ones that create pages on our website.

You should see:

pins

new_pin

edit_pin

pin

The one we want to focus on right now is 'pins', in fact; you can head to your website and take a look at it right now:

https://pinterested-codemy.c9.io/pins (or whatever your URL is)


(https://pinterested-codemy.c9.io/pins)

As you can see, there isn't much there yet, because we haven't added any actual pins yet. But you can see the link that says "New Pin" and if you click on it, you'll find a page where you can create and upload a pin.


(https://pinterested-codemy.c9.io/pins/new)

The only thing that the form asks for is the "Description", and that's because when we ran our 'rails g scaffold' command, the only item we listed was description:string.

"But, I thought we would be making pins with images?!" yeah - yeah, one step at a time! Right now I just want to show you how to get things rolling with a simple description; we'll add images soon.

So create a pin. Type in something into the description field and click the "Create Pin" button. Then head back to:

https://pinterested-codemy.c9.io/pins (or whatever your URL is)

You should see your pin listed there. Go ahead and create a few more pins, just to get things rolling:


(https://pinterested-codemy.c9.io/pins - with a few pins added)

All your pins are listed on the pins page in a simple table. But notice next to each pin there are three links: "Show, Edit, Destroy". Those links do exactly what you would think they would do.

Go ahead and play around with them a bit...I'll wait.

THAT'S CRUD!

Before we move on, we need to discuss something that's very fundamental to web development, and that's CRUD.

Create

Read

Update

Destroy

We've just generated a simple scaffold, but that tool is one of the most powerful things you'll ever come across in web development. Why? Because that simple scaffold has given us the tools and ability to handle CRUD (Create, Read, Update, and Destroy).

You can see in our simple Pinterest app that we now have the ability to Create something (a simple pin with description text). We can View that pin (Read it), we can edit it (Update it), and we can delete it (Destroy it). CRUD.

So what?

Take a minute and think about every major website in the Internet. Don't they pretty much all just do CRUD?

Think about Twitter...it's a massive website, but when you get right down to it, when you use Twitter, you're only really Creating a Tweet, Reading a Tweet, Updating a Tweet, or Deleting a Tweet...CRUD!

What about Facebook? Create a Facebook post, Read a Facebook Post, Update a Facebook Post, or Delete a Facebook Post...CRUD!

Youtube? Create a Video Post, Watch a Video (read), Updating one of your videos, or Delete a Video...CRUD!

What about a Blog? You create a blog post, read a blog post, update your blog post, or delete your blog post...CRUD!

Everything, and I mean everything basically just breaks down to CRUD. It's one of the fundamental building blocks of the Internet and we just learned how to handle it with one simple command in Rails.

One simple command and Rails handles everything about it! It's really pretty amazing, and it gives you an incredible tool that you can use to build just about anything online.

Sure, our simple pin description isn't much right now...but we'll tinker with it a bit and make it more impressive (adding images etc).

Right now, I just want you to focus on CRUD, and how the Rails g Scaffold command has given you the ability to create CRUD. We have more to learn, but this is the first step and it's a big one.

SCAFFOLD VIEWS AND CONTROLLER

Let's take a minute to look at some of the files that the 'rails g scaffold' command created. As I mentioned, you should have a new 'pins' folder in your /views/ directory. There should be six or seven files in that folder (some of which you can ignore - like the json ones).

The other files are the pages that allow us to create pins (new.html.erb), edit pins (edit.html.erb), show an individual pin (show.html.erb), and list all the pins (index.html.erb).

If you take a look at those files, you'll notice that most of them call a partial file to handle the actual form used to create a pin or edit the pin:



1 <%= render 'form' %>
2

That form partial file is also located in the pins folder, and is named _form.html.erb

You can go through those files (both the views and the form partial) and play with the look of them. I'll leave it as homework for you to make them look the same as our Devise views (use the Bootstrap 'form' class and 'panel' class like we used for our Devise views).

Besides the views, the 'rails g scaffold' command also created a new controller to handle all of this CRUD stuff. The controller is located in /app/controllers/pins_controller.rb and should look like this:



/app/controllers/pins_controller.rb
1 class PinsController < ApplicationController
2 before_action :set_pin, only: [:show, :edit, :update, :destroy]
3
4 respond_to :html
5
6 def index
7 @pins = Pin.all
8 respond_with(@pins)
9 end
10
11 def show
12 respond_with(@pin)
13 end
14
15 def new
16 @pin = Pin.new
17 respond_with(@pin)
18 end
19
20 def edit
21 end
22
23 def create
24 @pin = Pin.new(pin_params)
25 @pin.save
26 respond_with(@pin)
27 end
28
29 def update
30 @pin.update(pin_params)
31 respond_with(@pin)
32 end
33
34 def destroy
35 @pin.destroy
36 respond_with(@pin)
37 end
38
39 private
40 def set_pin
41 @pin = Pin.find(params[:id])
42 end
43
44 def pin_params
45 params.require(:pin).permit(:description)
46 end
47 end
48

That's quite a bit more stuff than our old home_controller.rb file that we created back at the beginning of this book when we made our original index and about page! But it makes sense that this file would be a little more complicated, since this controller needs to handle all the CRUD stuff.

Take a look through this controller file. You don't need to understand everything that's going on in there at this point...but you should get at least a small sense of what's happening.

Look at the different 'def' sections. Notice how they sort of follow along with CRUD? There's a 'def show' (Read from CRUD), there's a 'def new' and 'def create' (Create from CRUD), there's a 'def edit' and 'def update' (Update from Crud), and a 'def destroy' (Destroy from CRUD).

Apart from that; there's some stuff towards the bottom, private and 'def pins_params' that we'll fiddle with later.

Like I said though, you don't really need to know what all this is doing at the moment, but you need to have a sense of it and realize that this controller is handling our CRUD stuff for us.

ADDED TABLE TO OUR DATABASE

Our database is getting more and more complicated. Earlier, all it did was handle users signing up, logging in and out, and editing their profiles. Now it has to handle all of the pins that people upload.

Luckily, Rails still handles all this database stuff for us behind the scenes, but we can take a look at a sort of snapshot of what our database looks like by checking out our database schema file, located at: /app/db/schema.rb

You'll remember that the /app/db/ directory is where our migration files are located, so it makes sense that this is where our schema.rb file is located.

Basically a schema.rb file is just a snapshot of our current database. You won't need to ever do anything with this file (you won't need to edit it or anything), but it's nice to take a quick peek at it from time to time. Let's do so now...



/app/db/schema.rb
1 ActiveRecord::Schema.define(version: 20141229144241) do
2
3 create_table "pins", force: true do |t|
4 t.string "description"
5 t.datetime "created_at"
6 t.datetime "updated_at"
7 end
8
9 create_table "users", force: true do |t|
10 t.string "email", default: "", null: false
11 t.string "encrypted_password", default: "", null: false
12 t.string "reset_password_token"
13 t.datetime "reset_password_sent_at"
14 t.datetime "remember_created_at"
15 t.integer "sign_in_count", default: 0, null: false
16 t.datetime "current_sign_in_at"
17 t.datetime "last_sign_in_at"
18 t.string "current_sign_in_ip"
19 t.string "last_sign_in_ip"
20 t.datetime "created_at"
21 t.datetime "updated_at"
22 end
23
24 add_index "users", ["email"], name: "index_users_on_email", unique: true
25 add_index "users", ["reset_password_token"], name:
26 "index_users_on_reset_password_token", unique: true
27
28 end
29

You'll notice that there are two tables in our database; one to handle all the Devise things ("users"), and one to handle all our pins stuff ("pins").

You'll also notice that both tables have timestamp information that was created automatically when we created the table (Rails does that for us - for instance, in our "pins" table we only wanted it to add a description:string, but our pins table also has a t.datetime "created_at" column and a t.datetime "updated_at" column).

Like I said, there's nothing we need to do here, I just wanted to make you aware of the schema.rb file. You should get into the habit of taking a look at that file every time you make any sort of change to the database (anytime you push a migration, for instance)... just to keep an eye on things.

CHECK OUT OUR PINS INDEX PAGE

Finally, let's take a moment to check out our main pins index page. This is going to become one of the most important files of our site, because this is where we're going to do most of the work to make our site look and feel like pinterest. Let's take a look at what we have there so far:



/app/views/pins/index.html.erb
1 <h1>Listing pins</h1>
2
3 <table>
4 <thead>
5 <tr>
6 <th>Description</th>
7 <th colspan="3"></th>
8 </tr>
9 </thead>
10
11 <tbody>
12 <% @pins.each do |pin| %>
13 <tr>
14 <td><%= pin.description %></td>
15 <td><%= link_to 'Show', pin %></td>
16 <td><%= link_to 'Edit', edit_pin_path(pin) %></td>
17 <td><%= link_to 'Destroy', pin, method: :delete, data: { confirm: 'Are you
18 sure?' } %></td>
19 </tr>
20 <% end %>
21 </tbody>
22 </table>
23
24 <br/>
25
26 <%= link_to 'New Pin', new_pin_path %>
27

You'll notice the main layout of the page is a basic HTML table. If you don't have a lot of experience with HTML and aren't familiar with tables, don't worry. We won't be keeping the table (eventually we'll remove the table and use Bootstrap panels to make each 'pin' look like a pinterest pin).

The most interesting stuff happens on lines 12-20. Those are the lines that call into our database, look up our pins table, and output each pin onto the screen.

Line 12 is a basic Ruby loop <% @pins.each do |pin| %> that says "for each pin in our pins table, do something"; and the 'something' are lines 14-18 (ie output the pin.description and links to show, edit, or destroy the pin).

The reference to pin.description is the description:string that our 'rails g scaffold pins description:string" command generated (ie each pin's description).

We'll play with this file again soon; when we finally add images into the mix.

UPDATING THE NAVBAR

Now that we have a few more pages in our site, it's time to update the Navbar with links to those pages; specifically the pins index page and the 'add new' pin page:

https://pinterested-codemy.c9.io/pins (or whatever your URL is)

https://pinterested-codemy.c9.io/pins/new

We don't mind showing the world our pins index page, but we probably only want people who are signed in to be able to directly access the "add new" pin page (in the next chapter we'll get into authentication). Remember how we split the Navbar up based on whether a user is signed in or not?



/app/views/home/_header.html.erb
1 <nav class="navbar navbar-default" role="navigation">
2 <div class="container">
3 <!-- Brand and toggle get grouped for better mobile display -->
4 <div class="navbar-header">
5 <button type="button" class="navbar-toggle collapsed" data-
6 toggle="collapse" data-target="#bs-example-navbar-collapse-1">
7 <span class="sr-only">Toggle navigation</span>
8 <span class="icon-bar"></span>
9 <span class="icon-bar"></span>
10 <span class="icon-bar"></span>
11 </button>
12 <%= link_to 'Pinterested', root_path, class: 'navbar-brand' %>
13 </div>
14
15 <!-- Collect the nav links, forms, and other content for toggling -->
16 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
17 <ul class="nav navbar-nav navbar-right">
18 <li><%= link_to 'Home', root_path %></li>
19 <li><%= link_to 'About Me', home_about_path %></li>
20 <li><%= link_to 'List Pins', pins_path %></li>
21 <% if user_signed_in? %>
22 <li><%= link_to 'Edit Profile', edit_user_registration_path %></li>
23 <li><%= link_to 'Add Pin', new_pin_path %></li>
23 <li><%= link_to 'Logout', destroy_user_session_path, method: :delete %></li>
24 <% else %>
25 <li><%= link_to "Login", new_user_session_path %></li>
26 <li><%= link_to "Join", new_user_registration_path %></li>
27 <% end %>
28 </ul>
29 </div><!-- /.navbar-collapse -->
30 </div><!-- /.container-fluid -->
31 </nav>
32

We've done a lot in this chapter! Be sure to save your changes:



1 $ git add .
2 $ git commit -am 'added pins scaffold, updated navbar'
3 $ git push
4 $ git push heroku master
5 $ heroku run rake db:migrate
6

Be sure to run the rake db:migrate command on Heroku since we added a new element to our database (the pins table).

In the next chapter we'll look at Authentication and set up safeguards that only allow signed-in users to add pins to our database.