And so we've finally made it to the chapter where everything comes together!

With all that we've learned, we're ready to start using Ruby on Rails to start building our very own web application, one that with the core functionality of this very web application.

In case you haven't heard, Ruby on Rails is a web application framework written in Ruby.

8.1 | Testing

Before we do anything though, something should be pointed out.

From here, we are going to be building a web application, but we're going to leave out one critical part of the process: testing.

Tests (or specs) are what prove that your application works as you intend it to. Without them, you cannot confidently push changes to production because you do not know that your new features or fixes actually work, let alone be sure that you haven't inadvertently broken something that was written earlier.

Testing is not some trend, nor is it a nice-to-have; testing is the difference between a prototype and a professional, production application. If you intend for others to use the application you are building (and especially if you are intending to sell it to them), it is imperative that you have a thorough test suite for that application. Without one, you cannot be certain that your application works as advertised and that is every bit as bad as it sounds.

In the resources, you'll find a book on testing. This book will more than get you started in the right direction and I encourage you to work your way through it anytime after you complete this book, but before you push a real application of your own live.

With that out of the way, let's get to it!

8.2 | Getting Started

So Rails is a web application framework, but as we saw earlier with our $ which rails, it is also a Bash command: rails.

If you read through the section on gem, you've already run $ gem install rails and have it installed on your system. If you haven't, kick back for 15 minutes (okay, not that long) and take a chance to do that now.

And it's actually this rails command that will be getting us started on building our web app.

8.2.1 | Creating a New Rails Project

It's finally time to create our Rails application, one that will grow up to function like the system that allowed you access to this very sentence.

I have a /home/brad/rails directory to store my Rails projects and recommend having something like this to help keep you home directory from growing out of control. Assuming you're in your home directory, you can make and change into on for yourself like so:

$ mkdir rails; cd rails

Now we'll use the rails command to generate a brand new application.

$ rails new book

This will generate a ton of output, and then send us back to a Bash prompt.

Let's see what happened.

$ ls
book
$ cd book; ls
app     config.ru  doc      lib  public    README.rdoc  test  vendor
config  db         Gemfile  log  Rakefile  script       tmp

So rails created a new folder named book (just like we asked) and populated it with various directories and files.

We'll get an overview of each of these files and directories in a bit, but we've actually got a fully functioning Rails app at this point.

Well, it doesn't do anything specific that we want it to, but it is fully functional...

8.2.2 | Starting the Rails Server

If it's fully functional, then we should be able to visit something in our web browser, right?

We sure can.

First, we'll need to fire up rails server, our means of accessing our Rails app. Assuming your current directory is rails/book:

$ rails server
=> Booting WEBrick
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-08-14 19:08:45] INFO  WEBrick 1.3.1
[2012-08-14 19:08:45] INFO  ruby 1.9.3 (2012-04-20) [x86_64-linux]
[2012-08-14 19:08:45] INFO  WEBrick::HTTPServer#start: pid=24181 port=3000

Let that continue to run in the terminal because it will need to be running to respond to incoming web requests. But before we make any requests, there are some important things to note here.

First of all, from the first line of output from this command it's clear that WEBrick is being used (as the web server), and not Thin as we talked about earlier. This is because WEBrick is the default web server for Rails and we haven't added another one to Gemfile.

Next, you'll notice that first the web server boots up and then the Rails application is started. The order isn't particularly important to us, but remember that these are two separate things. The Rails app will remain the same, even after we've switched out WEBrick for Thin, because Rails just wants a Rack compliant web server; it doesn't care which one we use, it just needs something to field HTTP requests for it.

Additionally, we see a URL on the same line that announced the starting of the Rails app: http://0.0.0.0:3000. This is one of the URLs we can use in the browser to make requests to the application.

Finally, we can also see that Ctrl-c (a.k.a. ^C) can be used to stop the server. The web server will run indefinitely, since it needs to respond and keep responding to incoming HTTP requests, so if you ever want your terminal back, you'll have to Ctrl-c your way there.

With the server now running, let's go to Chrome and visit our application at any one of the following: http://localhost:3000 http://127.0.0.1:3000 http://0.0.0.0:3000

I use the first, because it doesn't require typing a bunch of dots and numbers, but they will all get you to the same place.

In case you're wondering, the first two use what is referred to as a loopback to make requests to the local machine and the last two take the form http://[ip address]:[port].

An interesting thing to note here is the :3000 on the end of these addresses. If you hit http://localhost all by itself, you'll probably get a message from Chrome saying Oops! Google Chrome could not connect to localhost like I did, but you definitely won't be looking at your Rails app.

If you don't specify a port in your URL, the browser will resolve this to mean that you want to use port 80. This port is what is commonly used to serve hypertext content across the web, but it requires superuser permissions and since that's just one more hassle we'd like to avoid, we instead use port 3000 for development on our own machines.

Regardless of which URL you chose, we'll find ourselves on a page with a Rails logo and greeted by a message saying Welcome aboard You're riding Ruby on Rails.

Click the About your application's environment link and we'll see some familiar terms, including:

  • Ruby version
  • RubyGems version
  • Rack version
  • Rails version

And then a little further down:

  • Application root: /home/brad/rails/book
  • Environment: development
  • Database adapter: sqlite3

Also be sure to check out the links listed in the sidebar Browse the documentation later; they're all awesome resources.

Let's talk about these last three items.

Application root is fairly straightforward. This is the root directory for the Rails application, the one where you started the server with $ rails server earlier. This directory is also commonly, probably more commonly, referred to as Rails root.

Environment in Rails can be either development, test, or production (by default). We won't be looking at test, but we will be using both development and production. In fact, we're obviously using the development environment right now, according to the text on this page we were just served.

If you look back at the output from $ rails server, you'll see that development is mentioned on that second line as well.

So what good is it to have different environments?

Well, there are many of them, but as an example let's consider that next line: Database adapter: sqlite3

Essentially this is specifying what kind of DBMS (Database Management System) we will be using to store information with our Rails app. As you can see, we are using SQLite3 for this purpose in our development environment.

Who would want to use different DBMS's and why?

Actually, we want to. Furthermore, we will be using different DBMS's during this book: SQLite3 (sqlite3) in our development environment and PostgreSQL (pg) in our production environment.

Why?

SQLite3 is serverless and thus does not take a painstakingly long time to install and configure locally, while PostgreSQL can. In short, SQLite3 lets us get up and running fast.

bundle install was run as part of our rails new above.

If SQLite3 is so great, why don't we use it in production too?

SQLite3 is great for development, but poorly suited for production. The reason for this is that SQLite3 was written to be easy to install and use on a client (such as your laptop or even your phone) for light-weight applications, but it does not scale well to accommodate thousands of users hitting it simultaneously. Basically, SQLite3 was created with a single user in mind, and so we use it here as one user running web app locally.

PostgreSQL on the other hand throws around statements like "most advanced open source database" and "sophisticated", and deserves to. It was designed to handle the load of having tons of users vying for its time. Besides being generally fit for the task, it is also the default DBMS used by Heroku. And since we'll be using Heroku for (production) hosting, we will also choose PostgreSQL as our production DBMS.

We'll be looking at Heroku shortly. It'll be great.

There are plenty of other configuration options that operate on a per environment basis, but DBMS's are certainly a good example.

So now that we've talked all about using different web servers and DBMS's, let's see how we can change them.

8.2.3 | Changing the Gemfile

First, let's change our web server from WEBrick to Thin.

If your server is still running, shut it down with Ctrl-c and then open up the file named Gemfile in Rails root. You'll probably notice that webrick isn't listed anywhere inside. This is because Rails will pick WEBrick by default as the web server if we don't specify anything else. So let's specify something else!

We need to add gem 'thin' anywhere in this file to install and use Thin, but I prefer some method with my madness when it comes to Gemfiles, so I'm going to place it right after gem 'rails'. The top of my Gemfile ends up looking like this:

source 'https://rubygems.org'

gem 'rails', '3.2.8'

gem 'thin'

...

And again, as was noted in the last chapter, please be sure to use Rails version 3.2.14 or later if you plan to run a Rails application in production. (That is, use gem 'rails', '~> 3.2.14' in your Gemfile instead.) If you're just running the applciation locally though, you'll be fine.

So now that we've updated our Gemfile, we have to let Bundler know that we want any new gems downloaded and installed for our project, so let's do that:

$ bundle install

thin should show up somewhere towards the end of the output but you can also run $ bundle show thin to see specifically where it got installed.

Now let's fire everything back up.

$ rails server
=> Booting Thin
...

There, now we're using Thin.

Now, let's adjust Gemfile to contain the PostgreSQL gem pg in addition to sqlite3.

This change is different from the change to Thin though, because we want SQLite3 only in development and PostgreSQL only in production. We can easily let Rails know that this is what we want using group, as seen in my new and improved Gemfile:

source 'https://rubygems.org'

gem 'rails', '3.2.8'

gem 'thin'

group :development do
  gem 'sqlite3'
end

group :production do
  gem 'pg'
end

...

Now that we have a DBMS that works with Heroku in our Gemfile, we're all set to deploy to production.

8.2.4 | Git and Deploying Our Project

Deployment is the act of pushing your newest code up to a remote server, most commonly a production environment, and can be accomplished many different ways with Rails, but since we're using Heroku, the method is incredibly easy: we use Git.

This may seem like an incredibly early stage at with to do this, but it's a good habit to get into.

When we deploy to production, we'll often run into hiccups that we didn't experience in development. This happens because we're running our code on a different machine and, for example, something that we take for granted might not be installed on it.

So you can wait, but I've found that it's best to do deploy from the start so that we can resolve our issues as they crop up instead of all at once right before we want to launch.

Also, Heroku makes this ridiculously easy, so there's really no reason not to.

An additional benefit here is that this will provide you with a means of accessing your application from anywhere with an Internet connection. This can make it easier to collaborate with teammates or simply share your app with family and friends.

Okay, to start things off, we're going to have to create a new Git repository for our project. From Rails root:

$ git init

Then add all our files:

$ git add .

And commit them:

$ git commit -m 'initial commit'

Now we'll need to install the Heroku Toolbelt.

Just run the installer or copy/paste the wget line into Bash and follow the login instructions.

Assuming that you now have the heroku command installed on your system, have an account, and have gone through heroku login, we can tell Heroku to create a place for our app:

$ heroku create
Creating calm-depths-5591... done, stack is cedar
http://calm-depths-5591.herokuapp.com/ | git@heroku.com:calm-depths-5591.git
Git remote heroku added

There's quite a bit going on here, let's go line by line.

First, we can see that Heroku is creating our app and (since we didn't tell it otherwise), assigning a random name. In my case, this look like: Creating calm-depths-5591... done, stack is cedar

As I write this, 'cedar' is the newest (and the default) stack for Heroku. Here, stack refers to the set of technologies they have set up and that work together to support our application. Cedar supports the newest rubies and Rails.

Next, we see the following: http://calm-depths-5591.herokuapp.com/ | git@heroku.com:calm-depths-5591.git

The URL to the left of the | will take us to our new app, except that right now all that's there is the message Heroku | Welcome to your new app! because we haven't pushed our application up yet.

Speaking of pushing, to the right of the pipe is a URL for the remote Git repository that Heroku has prepared for us. By pushing to this repository we will be able to update and restart our application on Heroku.

So what do we have to do with that Git URL?

Nothing, as you might guess from the last line of output: Git remote heroku added.

heroku went ahead and kindly added this remote repo URL to our .git/config for us, naming it heroku.

So we're all set. Let's push to Heroku!

$ git push heroku master

This will take a little while and output quite a bit, but you'll know it's finally done once you get a blinking cursor and Bash prompt again.

Also keep in mind that this git push is nothing magical, it takes the simple form $ git push [remote] [branch] to push the master branch up to our new heroku remote repo.

My push output looks something like this:

$ git push heroku master
Counting objects: 1184, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (1161/1161), done.
Writing objects: 100% (1184/1184), 455.59 KiB | 156 KiB/s, done.
Total 1184 (delta 833), reused 0 (delta 0)

-----> Heroku receiving push
-----> Ruby/Rails app detected
-----> Installing dependencies using Bundler version 1.2.0.rc.2
       Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment
       Fetching gem metadata from https://rubygems.org/.......
       ...
       ...
-----> Launching... done, v5
       http://calm-depths-5591.herokuapp.com deployed to Heroku

To git@heroku.com:calm-depths-5591.git
* [new branch]      master -> master
$

There's quite a bit in the middle there in the middle with the ----->'s, but at the beginning and end you can see that it's otherwise just a simple Git push.

Revisit your herokuapp URL and you'll this time be informed You're riding on Rails! by your Rails app that is now hosted on Heroku!

If you want to push anything else up to Heroku, just use the following commands from Rails root:

$ git add .
$ git commit -m 'COMMIT MESSAGE GOES HERE'
$ git push heroku master

8.3 | Starting the Project

There sure was a lot to cover to get here, but we're finally ready to make our Rails application do something.

8.3.1 | Brainstorming

As I write this, I haven't yet built the application myself, so we can think this through together.

This will probably be a little strange to read now that you've used this application to read a full seven chapters so far, using all this functionality already, but that doesn't the fact that I still haven't fully planned or implemented it!

All right, first up, here's the overarching idea for the functionality of the Rails app, in plain English:

The application will be used to publish a single book to the web, for viewing in a web browser.

Additionally, the layout should be responsive and adjust to suit users who are viewing the site on a mobile device (with a small screen).

To view the chapters, users must be registered in the system; this process will require that they pay a one time fee for access to the book.

To edit the chapters, there should be an admin interface (accessible only by the author) that permits the uploading of markdown documents for the chapters.

While viewing chapters, users should be able to keep track of their progress with a bookmark. They should also be able to point out errors in the text. These errata should be emailed to the author by the application.

Here's a brain dump of what I generally see the app needing:

Models:
  Chapter
  User
  Mark
    Bookmark
    Errata

Styling:
  Twitter Bootstrap

Misc:
  Home Page
  File Upload/Markdown conversion
  Mailer for errata
  Billing

We'll talk about models in more detail shortly, but for now just think of them as representing "things we want to persist in the database".

There are a few places that could make sense to start, but let's start with implementing the chapter functionality, since there isn't really a site without a book, and no book without chapters.

There are some critical but involved portions of this, like the admin and upload functionality, so for the time being, we'll just work on getting some absolute barebone chapter stuff working.

8.3.2 | Rails Generators

Now we could just start hand writing all the necessary directories and files to get going here, but rails is more than happy to do some of the really rudimentary work for us. Here we'll ask it to help us out using Rails generators, more specifically, the scaffold generator.

8.3.2.1 | Scaffolding

The primary goal of scaffolding is to create a new resource (e.g. chapters), but we also get much more for free. Scaffolding not only creates a resource, but it will also sets up things for us on several levels, from the database to the routing to the user interface.

The result will be a UI (user interface) that will be incredibly basic, but it will support CRUD actions using Rails RESTful routes and allow for persisting changes in the database, all without any additional work from us.

To use scaffolding, we just need:

  1. a name for the resource (e.g. Chapter)
  2. the resource attributes and their types in the form [attribute_name]:[type] (e.g. title:string)

Notice that the resource name is capitalized. The reason for this is that that it ends up as a Rails model which we'll see soon enough is just a fancy Ruby class. ...and Ruby classes must start with a capital letter.

Enough talk, let's get some scaffolding up in here.

$ rails generate scaffold Chapter title:string
      invoke  active_record
      create    db/migrate/20120816003923_create_chapters.rb
      create    app/models/chapter.rb
      invoke    test_unit
      create      test/unit/chapter_test.rb
      create      test/fixtures/chapters.yml
      invoke  resource_route
      route    resources :chapters
      invoke  scaffold_controller
      create    app/controllers/chapters_controller.rb
      invoke    erb
      create      app/views/chapters
      create      app/views/chapters/index.html.erb
      create      app/views/chapters/edit.html.erb
      create      app/views/chapters/show.html.erb
      create      app/views/chapters/new.html.erb
      create      app/views/chapters/_form.html.erb
      invoke    test_unit
      create      test/functional/chapters_controller_test.rb
      invoke    helper
      create      app/helpers/chapters_helper.rb
      invoke      test_unit
      create        test/unit/helpers/chapters_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/chapters.js.coffee
      invoke    scss
      create      app/assets/stylesheets/chapters.css.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.css.scss
$

There's a lot going on there, but essentially Rails just created and modified a bunch of files to create some basic functionality for a new resource named "Chapter".

This may seem a bit like magic, but it ends up being very similar to what we'll shortly be doing ourselves with views. The difference being that what we just saw Rails generate for us is a lot of code for use in the application (mostly Ruby, but not exclusively), whereas we'll be mostly be looking to generate HTML and JSON to serve to the user. Clever, yes. Magic, no.

Though thorough, scaffolding didn't take care of everything. We can see this by firing up $ rails server and visiting http://localhost:3000/chapters to try to view the index for our new chapter resource.

Could not find table 'chapters'

The reason for this error is that we haven't migrated the database to create a table for chapters.

Remember the data for our resource will need to be persisted in a database.

Rails will use the plural of the resource name (e.g. "chapters") as the table name and the attribute names as the column names.

The scaffolding generator did create a migration, db/migrate/20120816003923_create_chapters.rb, for this purpose, but we still need to tell rake to run it.

Speaking of which, you know what I forgot? Our chapters are going to be pretty boring with just titles and no bodies.

Before we run the migration that will create our chapters table, let's generate another migration that will add a column for body to the table.

8.3.2.2 | Migrations

To fix my mistake we can use a different generator named migration to create a migration all by itself that will add another column:

$ rails generate migration add_body_to_chapters boody:text
      invoke  active_record
      create    db/migrate/20120816011108_add_body_to_chapters.rb

This time we will be using the type text instead of string for this field to accommodate the greater length of the chapter body.

Also, we can see that each migration begins with a jumble of numbers, that upon closer inspection are timestamps. This is done to ensure that when the migrations are run on a new system, they are run in the proper order, resulting in the same database schema for each environment.

To run all (read: both) of our migrations, we'll use rake:

$ rake db:migrate
==  CreateChapters: migrating =================================================
-- create_table(:chapters)
   -> 0.0026s
==  CreateChapters: migrated (0.0029s) ========================================
 
==  AddBodyToChapters: migrating ==============================================
-- add_column(:chapters, :boody, :text)
  -> 0.0004s
==  AddBodyToChapters: migrated (0.0007s) =====================================

You may get an error trying to do this, as I often do:

$ rake db:migrate
rake aborted!
You have already activated rake 0.9.3.beta.1, but your Gemfile requires rake 0.9.2.2. Using bundle exec may solve this.

In which case, you should take the advice at the end and use $ bundle exec rake db:migrate instead.

rake comes from a gem itself and you might have one version of it installed on your system and another required in your Gemfile. Using bundle exec tells Bundler to run the command following it and to do so using the version of that command specified in your Gemfile.

You might be wondering why we don't have to do this with the rails command since it too is packaged as a gem. Though we may not be doing anything explicitly, rails itself is designed to avoid this kind of versioning issue. If we run rails within a Rails project, rails is actually running script/rails within the project (a file that was generated when we first ran $ rails new book).

We can see that this ran both of our migrations: CreateChapters and AddBodyToChapters

But upon closer inspection, we see that I messed up yet again.

add_column(:chapters, :boody, :text). boody. Yeah, great job, Brad.

To rollback my mistake (but not my humiliation) we can do the following:

$ rake db:rollback
==  AddBodyToChapters: reverting ==============================================
-- remove_column("chapters", :boody)
   -> 0.0069s
==  AddBodyToChapters: reverted (0.0069s) =====================================

This will bring the database back a state before the last migration and it will irrevocably, unapologetically destroy all data stored in the columns/tables that are dropped by doing so.

If we wanted to go back several migrations, we can use a Bash variable STEP to tell rake. The following would revert the last three migrations:

$ rake db:rollback STEP=3

Now that we have reverted the migration, we have removed the boody column from the table in the database, but we still need to adjust the migration to use the proper field name.

### db/migrate/20120816003923_create_chapters.rb ###

class AddBodyToChapters < ActiveRecord::Migration
  def change
    # DERP: add_column :chapters, :boody, :text
    add_column :chapters, :body, :text
  end
end

Comments are mine, used to indicate filename (top) and changes.

And with that, we can re-run the migration:

$ rake db:migrate
==  AddBodyToChapters: migrating ==============================================
-- add_column(:chapters, :body, :text)
   -> 0.0006s
==  AddBodyToChapters: migrated (0.0007s) =====================================

And now everything is as it should be with the database.

Be sure when rolling back migrations that you rollback first, then make the change, otherwise rake will try to drop a column that doesn't exist and you'll probably end up with body and boody when you re-run the new migration. ...or get an error.

Now that we have that all taken care of, let's take a look at our CRUD scaffolding. Start up the server and refresh the page for /chapters.

No error this time!

Click around some and see that you can in fact create, read, update, and destroy all the chapters you like. ...well, chapter titles.

Why isn't there anything in the UI to add a chapter body? We made a migration for it didn't we?

We sure did. The problem though is that the views that make up the CRUDy user interface were built by the scaffold generator, and we only told that generator that we wanted a title for our chapters. Only later did we migrate the database to have a column for chapter bodies.

We'll add a means of editing the chapter body to the UI (user interface) later, but first we have a couple more things to play around with.

There's one outstanding question in particular: how did Rails know what to do when we visited the /chapters path?

8.3.3 | Raking the Routes

We mentioned earlier that paths in Rails terminology are also referred to as routes and are used to direct traffic in the Rails app.

To start off, let's first see what routes we already have, using another useful Rails Rake task: rake routes

$ rake routes
    chapters GET    /chapters(.:format)          chapters#index
             POST   /chapters(.:format)          chapters#create
 new_chapter GET    /chapters/new(.:format)      chapters#new
edit_chapter GET    /chapters/:id/edit(.:format) chapters#edit
     chapter GET    /chapters/:id(.:format)      chapters#show
             PUT    /chapters/:id(.:format)      chapters#update
             DELETE /chapters/:id(.:format)      chapters#destroy

Running this Rake task isn't necessary, like rake db:migrate, it's just super convenient when you want to see a list of your routes.

You'll see some routes have their own names (e.g. chapters, new_chapter), but all of them have an HTTP verb, a path, and something of the form chapters#[action].

We'll see exactly what all this means and how these are defined in a minute, but before we look at the scaffolded files themselves, we need to understand what their purpose is and how they're organized.

What is our Rails app actually doing?

8.3 | MVC in Rails

Rails, like many web application frameworks, follows the Model-View-Controller (MVC) design pattern.

In the case of Rails, MVC is used to break up the responsibilities necessary to respond to an incoming HTTP request to the application. This leaves different parts of that process to different Ruby classes, which are saved in different files, such as models, views, and controllers.

In addition to models, views, and controllers, routes are another critical part of any Rails application. From our perspective as application developers in Rails, a route is where it all begins.

Before we dive in, let's see what a basic, successful HTTP request to and response from our server looks like from a high level.

Here are the steps:

  1. an HTTP request is received
  2. the Rails application maps the path from the request to a route
  3. this routes the request to a specific controller and action (often represented as [controller]#[action])
  4. the controller action uses the appropriate model to fetch the appropriate data from the database
  5. the controller action takes that model data and places it into the appropriate view to generate the HTTP response body (typically HTML or JSON)
  6. the HTTP response is then sent to the client

This is what it looks like when we're trying to retrieve data at least. It will obviously be slightly different if we are creating, updating, or destroying something.

In summary, the roundtrip from a execution flow standpoint looks something like this:

HTTP request received -> route -> controller#action -> model -> back to controller#action -> view -> back to controller#action -> HTTP response sent

While that is exactly what goes on in the app, we won't need to directly mess with the request or response ourselves, Rails will just handle it.

Our responsibility is to handle everything from routing to fully rendered view.

All right, here we go!

8.3.1 | Routes & Controllers

Routes

Remember how we were able to visit http://localhost:3000/chapters for our Rails app after we ran our scaffold generator (and migrated the database)?

You may have correlated that with this line from rake routes:

chapters GET    /chapters(.:format)          chapters#index

If so, you'd be correct. But were does that come from?

This route is defined inside of config/routes.rb, along with every other route for our application.

Removing all of the comments, this is what mine looks like right now:

### config/routes.rb ###

Book::Application.routes.draw do
  resources :chapters
end

To be honest, I couldn't write this off the top of my head, so don't worry if it looks involved. Do notice that it is all just plain Ruby though.

We see Book::Application.routes.draw do and can tell that we are eventually calling a method draw on something (object, class, or module, whatever was returned by Book::Application.routes) and passing it a block since do follows the call. Inside the block we are calling a method resources and passing it :chapters as the one and only argument.

Where did the resources :chapters line come from?

Looking back at the scaffold output, we'll see:

  invoke  resource_route
  route    resources :chapters

When we ran generated the scaffolding, Rails dumped this line into config/routes.rb for us.

So where is is the definition for /chapters? There's just one line that mentions :chapters.

Put simply, resources is a shortcut.

Instead of resources :chapters, we could have written out a definition for each individual route that we wanted:

Book::Application.routes.draw do
  # RESTful routes for CRUD(L)
  post   '/chapters'          => 'chapters#create'
  get    '/chapters/:id'      => 'chapters#show'
  put    '/chapters/:id'      => 'chapters#update'
  delete '/chapters/:id'      => 'chapters#destroy'
  get    '/chapters'          => 'chapters#index'

  # other routes
  get    '/chapters/new'      => 'chapters#new'
  get    '/chapters/:id/edit' => 'chapters#edit'
end

In this block in config/routes.rb we can use methods that represent different HTTP verbs (e.g. get, post) to define individual routes.

These calls might look novel, but they're still just Ruby. Take the first one for example; we are calling the method post and passing it the Hash '/chapters' => 'chapters#create' as the one and only argument.

A lot of what we'll see moving forward will seem somewhat foreign because there are a lot of different method names that we'll need to know in a given context, but ultimately if the file ends in .rb, it's all just Ruby, even if it seems like utter Rails magic.

As you can imagine, typing each of these routes out every time we added a new resource would be an absolute pain. It also wouldn't be DRY nor adhere to convention over configuration, another pillar of Rails philosophy.

In fact, "convention over configuration" is to blame for most of the works-out-of-the-box-edness of Rails. This can be great because things "just work", but it can also be a confusing because "convention" implies that you understand how something is normally done in Rails and how Rails is accomplishing it for you.

In this case it saves us from having to write out seven individual routes and, in the long run, saves us from having to repeat ourselves, since we won't have to do all of this work for each and every resource.

Notice though that it's convention over configuration, not convention without configuration. If we only needed an index and create action, we could use resources :chapters, only: [:index, :create] instead. If we didn't want new or edit actions, a resources :chapters, except: [:new, :edit] would suffice.

There is also a resource method that can be used for resources that are singular and a match method that works the same as the HTTP verb methods, except it can accept any kind of HTTP verb.

We'll be using these later.

Okay, now that we know how routes are defined, let's get back to thinking about routes themselves.

The HTTP verb and path are used to analyze the path of an incoming HTTP request and map it to a specific action within a specific controller using the format '[controller]#[action]'.

Take get '/chapters' => 'chapters#index' (that we get from resources :chapters) as an example. Here the controller is ChaptersController (which we'll see in a minute) and the action is index. This is compactly represented as 'chapters#index'.

You may see something like :controller => 'chapters', :action => 'index' to represent this instead sometimes, but this is unnecessarily verbose. ...unless you have a good reason for using it, like we will later.

Okay, from routes onto controllers, just as our request would go.

Controllers

The controller action pretty much calls the shots once it gets a request routed to it.

The controller is simply a Ruby class and the action is simply an instance method in that class.

Recalling the sequence listed earlier, we know that the controller makes use of the models and views. We haven't yet looked at the details of either of those yet, but that won't be necessary to understand the gis t of their purpose and use within a controller.

All right, let's pretend our Rails app received a GET request for /chapters/1.

If we consult our list of routes above, we'll find that that route matches /chapters/:id and is mapped to chapters#show, that is, the show action for the ChaptersController, so let's take a look at that action:

### app/controllers/chapters_controller.rb ###

class ChaptersController < ApplicationController
  # GET /chapters/1
  # GET /chapters/1.json
  def show
    @chapter = Chapter.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @chapter }
    end
  end
end

There's plenty of what seems to be Rails magic here, but it's all a very conventional Rails action. Let's dissect it.

First, there's the line dealing with the Chapter model: @chapter = Chapter.find(params[:id]).

We haven't looked at models yet, but we do know that this is using the database to fetch saved chapter data. Furthermore, it's stuffing the retun into a variable, an instance variable, named @chapter.

The fact that this is an instance variable becomes important shortly, but for now we just know that the data is being stored there.

Also on this line we'll see a class method call to Chapter.find. The Chapter seen here is the model for chapters.

But the full call is Chapter.find(params[:id]), what is params?

params is a Hash-like object that is an easy means of accessing parameters that were passed in with the HTTP request. With params[:id] we can get ahold of the chapter ID that came in with the request (e.g. the 1 in /chapters/1).

There's actually a request variable available within any controller action that has a ton more information pertaining to the request, but since it's much more than we normally care about, params is much easier.

Where did this ID come from?

Remember our hypothetical request to /chapters/1 and that the matched route was /chapters/:id? Well when that route gets matched, Rails does us a solid and drops the value matched for :id into params[:id] so we can get at it easily.

Grabbing parameters this way is something of a third means of parameter passing offered by Rails (in addition to the use of query parameters and POST data); it's kind of like baking a query parameter right into the path.

We could have been content with receiving the ID as a query string parameter (e.g. /chapters?id=1) instead, but since that's ugly, the Rails convention is to match values in the path itself for params.

Also, since all these methods (params in routes, query string parameters, POST data) are used to pass parameters into our application, Rails will treats them all the same and their key/value pairs will all end up in params.

One important thing to note here is that regardless of the method of transmission, parameters will always be strings. Sometimes you'll know you're getting a value and that that value will represent a number (as is the case here with the id), but you might forget it will be sent as a string.

In this case above, the find method can actually handle the integer ID as either a string or as an integer, but if you even think you might want a full fledged Fixnum for something you write, go ahead and waste the time and five keystrokes for a .to_i.

So in English, @chapter = Chapter.find(params[:id]) reads: "Find the chapter with an ID of [id that was passed in] and save it to the instance variable @chapter."

Now that we have the data for the chapter in hand, we have to create the proper HTML to display it. This means it's time for a view, which means that it's time for another look at the controller code.

respond_to do |format|
  format.html # show.html.erb
  format.json { render json: @chapter }
end

This is the pretty convention-heavy portion of this controller, despite a friendly comment that attempts to point us in the right direction.

First of all, for right now, we can ignore the format.json line because it doesn't concern us for our current request for HTML.

And this may sound kind of stupid, but the most important thing to learn here is that this is just the way to do this kind of thing in Rails.

Well, a way to do this kind of thing. There's actually a shorter way to do this in Rails 3 using respond_to in conjunction with respond_with that's available in Rails 3 and later.

Why wouldn't the scaffolds build it that way then?

Because this version is far more declarative and doesn't expect you to fully understand Rails conventions; it's a good learning tool.

Don't worry though, we'll look at the other way of doing things later on.

Within the block passed to respond_to, the block variable is a type of object that has different methods you can call on it that represent different response formats. In the code above we can see that two types are specified: html and json.

You may be wondering how it knows that we want HTML when we simply asked for /chapters/1. It doesn't really, but it does assume we do, as can be illustrated by the comment seen above the method definition:

# GET /chapters/1
# GET /chapters/1.json

You can even throw an .html on the end of the URL in the browser, making the path /chapters/1.html, and Rails will give you HTML for that too.

... but you'll have typed more than you needed to, an act that is generally frowned upon by pretty much everyone I've ever met.

It just assumes you want HTML if you don't say one way or another.

To see that both of these work though, go to a the "show" page for one of the chapters you created earlier, tack a .json on the end of the URL, and hit ENTER. That is, visit something like localhost:3000/chapters/1.json

I use an awesome Chrome extension called JSONView that will take a page of JSON like this, nicely format it for viewing, and add controls similiar to those for browsing JS objects in the Dev Tools console to collapse and expand objects/arrays. Highly recommend it.

JSON. Sweet.

Now try it with .xml.

Boom. No dice. Just as advertised.

As you might expect, mimicking the line for JSON, you could add a format.xml { render xml: @chapter } to the block and get the action responding to XML just like that.

So for the line of format.json above, there's a block with an explicit call to render that has @chapter passed in as an argument in a hash, but what's the deal with format.html? It doesn't have a block.

There are two pieces to this.

First, remember how we took special note of @chapter being an instance variable? This is because instance variables set in controllers are available in views and helpers. Because of this, we don't have to worry about passing the chapter data as an argument to a view, it's simply available to us as @chapter there too.

Second, if no block is passed in, the convention is to perform an implicit render by looking for a view in the directory under /app/views/ with a name that matches the controller (here, /app/views/chapters/), has a filname that matches the of the action (here, show), and has a filetype to match the format (here, .html). So that helpful comment we noted earlier, though not actually doing anything, does point us straight to the file used here: show.html.erb.

Oh, and there's an .erb there too. We'll cover that shortly.

So without yet knowing how views works, we do know what view is being used and the mechanism used to populate it with the proper data retrieved for specific chapter information from the database.

Oddly, the action does not have an explicit return or some special value at the end. We could assume some part of respond_to or some implicit render call from format.html was returning something, but that's not the case.

In fact, Rails just expects you to render once and then structure your logic such that no more renders are performed. So you can actually call render several times in one action, but Rails will complain like crazy if you do.

...trust me.

Ultimately, Rails will take whatever you've rendered and place it in the response body.

When explicitly calling render, we can also set things in HTTP response headers, such as status codes.

You can see examples of this elsewhere in the controller, using hash arguments like :status => :created (a 201).

When the action is done executing, the response is just taken care of automatically, sent back to the client without any special doing on our part. It's understood that that's what we're trying to do, so Rails just does it.

Well that's the process from the controller's perspective, let's take a deeper look at the other components.

8.3.2 | ORM & Models

Next stop on the tour is models. Let's jump right into the one generated by our scaffold:

### app/models/chapter.rb ###

class Chapter < ActiveRecord::Base
  attr_accessible :title
end

There's barely anything there!

Actually, we'll soon see that we get a ton of functionality from that very first line: class Chapter < ActiveRecord::Base.

The attr_accessible line essentially serves as a whitelist of attributes that can be written to the database under normal circumstances. We'll need to add :body to it, making the line attr_accessible :title, :body, so that we can update chapter bodies through the UI we'll adjust shortly.

:body wasn't there already because we didn't tell the scaffold we wanted it.

We'll look at why this is necessary later on when we discuss security.

And be careful not to confuse attr_accessible with attr_accessor (that we learned about in last chapter). attr_accessible is used in Rails to whitelist model attributes, whereas attr_accessor is a feature of Ruby to define attributes within a class.

Remembering back to our trip through Ruby, we know that this line is the beginning of a class definition for Chapter and that it inherits from ActiveRecord::Base. The inheritance here is crucial because it uses ActiveRecord to make our Ruby class into a Rails model, adding lots of functionality, like the Chapter.find that we saw in the controller.

There are alternatives to ActiveRecord, such as MongoMapper, but ActiveRecord is the canonical Rails solution.

ORM

ActiveRecord is an Object Relational Mapper (ORM).

What this means for us is that ActiveRecord will (1) query the database for us and (2) return the results to us as an object. This way we don't have to write our own SQL to query the database and or mess with structuring the result (though we could). It's pretty great.

Again, just because we're not writing the SQL does not mean that we are not responsible for understanding the security and performance concerns for what we are doing. After you've got a solid grasp of how this works in Rails, it's a good idea to check out what's going on behind the scenes.

The Rails Console

Let's take a look at some of the things ActiveRecord can do for us by playing around in the Rails console.

The Rails console is an incredibly useful tool: an IRB session that loads the Rails application. This is particularly useful for playing around with our models and saved data.

I've created two chapters, Foobar and Asdf, using the scaffolded CRUD interface. Let's take a look at them using $ rails console

$ rails console
Loading development environment (Rails 3.2.8)

# look ma! it's a regular IRB session!
> 2 + 2
=> 4

# counting all the chapters
> Chapter.count
(0.3ms)  SELECT COUNT(*) FROM "chapters" 
=> 2

# fetching an array of all the chapters
> Chapter.all
Chapter Load (0.4ms)  SELECT "chapters".* FROM "chapters" 
=> [#<Chapter id: 1, title: "Foobar", created_at: "2012-08-16 10:44:58", updated_at: "2012-08-16 10:44:58", body: nil>, #<Chapter id: 2, title: "Asdf", created_at: "2012-08-16 10:51:27", updated_at: "2012-08-16 10:51:27", body: nil>]

# getting the title string of the first chapter
> Chapter.first.title
Chapter Load (0.5ms)  SELECT "chapters".* FROM "chapters" LIMIT 1
=> "Foobar"

# getting the title string of the last chapter
> Chapter.last.title
Chapter Load (0.4ms)  SELECT "chapters".* FROM "chapters" ORDER BY "chapters"."id" DESC LIMIT 1
=> "Asdf"

# using a different syntax to fetch the title string 
# of the first chapter and checking it matches the other
> Chapter.all[0].title == Chapter.first.title
Chapter Load (0.1ms)  SELECT "chapters".* FROM "chapters" 
Chapter Load (0.1ms)  SELECT "chapters".* FROM "chapters" LIMIT 1
=> true

# mapping all the chapter titles into an array (like a boss)
> Chapter.all.map &:title
Chapter Load (0.4ms)  SELECT "chapters".* FROM "chapters" 
=> ["Foobar", "Asdf"]

# creating a new chapter
> Chapter.create title: "console test"
(0.2ms)  begin transaction
SQL (53.6ms)  INSERT INTO "chapters" ("body", "created_at", "title", "updated_at") VALUES (?, ?, ?, ?)  [["body", nil], ["created_at", Sat, 18 Aug 2012 05:06:47 UTC +00:00], ["title", "console test"], ["updated_at", Sat, 18 Aug 2012 05:06:47 UTC +00:00]]
(223.1ms)  commit transaction
=> #

# checking that the chapter count changed from 2 to 3
> Chapter.count
(0.4ms)  SELECT COUNT(*) FROM "chapters" 
=> 3

So that's some lookup and creation using ActiveRecord, let's see some more.

Comments and empty newlines are mine, but notice that each of the class methods that we called on our model required database queries and that those queries were printed out under our code.

You'll also see these printed when the server is running.

# simply initializing a new `Chapter`
> chapter = Chapter.new title: 'new chapter title'
=> #

# notice that this doesn't save to the database
> Chapter.count
(0.4ms)  SELECT COUNT(*) FROM "chapters" 
=> 3

# we have to explicitly save it to persist it in the DB
> chapter.save
(0.2ms)  begin transaction
SQL (8.8ms)  INSERT INTO "chapters" ("body", "created_at", "title", "updated_at") VALUES (?, ?, ?, ?)  [["body", nil], ["created_at", Sat, 18 Aug 2012 05:20:28 UTC +00:00], ["title", "new chapter title"], ["updated_at", Sat, 18 Aug 2012 05:20:28 UTC +00:00]]
(233.1ms)  commit transaction
=> true

# and now we have a new row in the database
> Chapter.count
(0.1ms)  SELECT COUNT(*) FROM "chapters" 
=> 4

# and here's the title from our latest chapter
> Chapter.last.title
Chapter Load (0.4ms)  SELECT "chapters".* FROM "chapters" ORDER BY "chapters"."id" DESC LIMIT 1
=> "new chapter title"

# we can change the title with the `title=` setter
> chapter.title = 'even newer chapter title'
=> "even newer chapter title"

# but it doesn't change the title of the chapter in the database
> Chapter.last.title
Chapter Load (0.2ms)  SELECT "chapters".* FROM "chapters" ORDER BY "chapters"."id" DESC LIMIT 1
=> "new chapter title"

# we first have to save
> chapter.save
(0.2ms)  begin transaction
(0.5ms)  UPDATE "chapters" SET "title" = 'even newer chapter title', "updated_at" = '2012-08-18 05:21:34.482715' WHERE "chapters"."id" = 4
(229.7ms)  commit transaction
=> true

# then it gets updated in the database
> Chapter.last.title
Chapter Load (0.4ms)  SELECT "chapters".* FROM "chapters" ORDER BY "chapters"."id" DESC LIMIT 1
=> "even newer chapter title"

# we can also blow it away with `destroy`
> chapter.destroy
Chapter Load (0.1ms)  SELECT "chapters".* FROM "chapters" ORDER BY "chapters"."id" DESC LIMIT 1
(0.0ms)  begin transaction
SQL (0.2ms)  DELETE FROM "chapters" WHERE "chapters"."id" = ?  [["id", 4]]
(224.0ms)  commit transaction
=> #

# and we're back to 3 chapters
> Chapter.count
(0.3ms)  SELECT COUNT(*) FROM "chapters" 
=> 3

So that's how we create, read, update, and delete, but what about that find method we saw earlier in the controller?

Let's look at some different ways to find a specific record.

# let's check to see what the ids for our all chapters are
> Chapter.all.map &:id
Chapter Load (0.6ms)  SELECT "chapters".* FROM "chapters" 
=> [1, 2, 3]

# title of the first chapter using `first`
> Chapter.first.title
Chapter Load (0.4ms)  SELECT "chapters".* FROM "chapters" LIMIT 1
=> "Foobar"

# title of the first chapter by passing its id to `find`
> Chapter.find(1).title
Chapter Load (10.4ms)  SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT 1  [["id", 1]]
=> "Foobar"

# remember that `find` doesn't care if it gets the id arg as a string?
> Chapter.find("1").title
Chapter Load (0.2ms)  SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT 1  [["id", "1"]]
=> "Foobar"

# and finally we can get all chapters that meet certain requirements with `where`
> Chapter.where title: "Foobar"
Chapter Load (0.1ms)  SELECT "chapters".* FROM "chapters" WHERE "chapters"."title" = 'Foobar'
=> [#<Chapter id: 1, title: "Foobar", created_at: "2012-08-16 10:44:58", updated_at: "2012-08-16 10:44:58", body: nil>]

So those are the basics of ActiveRecord, but rest assured there's much, much more inherited from ActiveRecord::Base. We may see some other functionality as we go, but we could probably get away with just knowing the methods we've seen above.

Models

So models in Rails are Ruby classes that allow us to read from and write to the database through the use of plain Ruby without having to mess with any SQL.

Models actually end up being where we end up placing a lot of our logic. This follows a Rails best practice: "fat model, skinny controller". This means that our controllers should have very little of our logic in them and that our model should do the bulk of the heavy lifting.

And yet we still haven't talked about the third piece of the puzzle.

8.3.3 | Views

So imagine we're in our controller action and we've used our model to grab a record. It's now time to render a view.

Specifically, let's look at show.html.erb, the file that helpful comment pointed us to earlier.

The erb in the file name stands for "Embedded Ruby", because, as we'll see shortly, this is a non-Ruby file with Ruby embedded in it that allows for content to dynamically be dumped into the document.

Notice that the double extension on this file of .html.erb too. This means that the file will be rendered using ERB and result in an HTML file.

These kinds of extensions will come up different places in Rails. Some examples are chapters.css.scss, chapters.js.coffee, show.html.haml, and show.json.rabl (depending on the gems you use).

### app/views/chapters/show.html.erb ###

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

<p>
  <b>Title:</b>
  <%= @chapter.title %>
</p>


<%= link_to 'Edit', edit_chapter_path(@chapter) %> |
<%= link_to 'Back', chapters_path %>

One particularly curious thing about this file is that it isn't a complete HTML document (i.e. doesn't have a <html>, <body>, etc). We'll address this later when we discuss layouts.

So there's clearly HTML in this view, but there's also something we've never seen before: <%= ... %>.

This is the part that puts .erb in the filename, and as you might expect, this is where you'll find embedded Ruby. The <%= ... %> is used to execute Ruby and print its return value (as a string) into the resulting file at that place. In a moment, we'll see that there is also a <% ... %> syntax (without the =) that simply executes Ruby in the view.

It's probably best to see this in action. Taking <%= @chapter.title %> as an example, fire up your server, hit a chapter show route (like /chapters/1), and do a Dev Tools inspect on the text Title. You'll see something like this:

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

<p>
  <b>Title:</b>
  Foobar
</p>


<a href="/chapters/1/edit">Edit</a> |
<a href="/chapters">Back</a>

Here we can see that the text Foobar was rendered into the HTML as the chapter title where we saw <%= @chapter.title %> in the ERB view.

Except you'll probably have something else that you named your chapter instead of Foobar...

We'll take a look at what the notice portion at the top is all about shortly, but for now let's take a look at the bottom of the view.

Specifically, we see that this:

<%= link_to 'Edit', edit_chapter_path(@chapter) %> |
<%= link_to 'Back', chapters_path %>

becomes this:

<a href="/chapters/1/edit">Edit</a> |
<a href="/chapters">Back</a>

Here the scaffolded view is making use of the link_to helper not just to generate text, as was the case with the chapter title, but to generate an entire HTML element (an <a>).

Notice the <%= before link_to. link_to just returns the string representation of the element and <%= prints that string right into the document.

link_to can take a variety of arguments, but the two seen here are pretty typical (and the bare minimum to be useful). In order, the arguments are:

  1. the link text (the <a>'s content)
  2. the link href (path or URL)

To get <a href="/chapters/1/edit">Edit</a> for the edit link, we could have used "/chapters/#{@chapter.id}/edit" for the second argument, but that would be a pain.

It's also a generally bad idea to hardcode paths like this unless you have good reason to do so.

Instead we use edit_chapter_path(@chapter) and chapters_path.

Do these two look kind of familiar?

We've actually seen a part of these method names before. Remember our rake routes output? Here are the relevant lines:

    chapters GET    /chapters(.:format)          chapters#index
 new_chapter GET    /chapters/new(.:format)      chapters#new
edit_chapter GET    /chapters/:id/edit(.:format) chapters#edit
     chapter GET    /chapters/:id(.:format)      chapters#show

Any of those strings printed before the HTTP verbs can be used as a URL helper by adding _path or _url to the end of them. chapters_path or new_chapter_url would be examples of this.

The URL helpers for index and new actions don't require arguments, because they will always have static locations. But in the case of URL helpers for existing, individual resources (e.g. chapter_path, edit_chapter_path), we'll also have to pass in an instance of that resource so that the URL helper has the proper id to place in the path/URL.

While we've got it open, let's go ahead and add the chapter body to show.html.erb:

<p>
  <b>Title:</b>
  <%= @chapter.title %>
</p>

<p>
  <b>Body:</b>
  <%= @chapter.body %>
</p>

This file will change significantly before we're done, but for the time being this will suffice for displaying the chapter body.

Moving on, let's take a look at the index view:

### app/views/chapters/index.html.erb ###

<h1>Listing chapters</h1>

<table>
  <tr>
    <th>Title</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @chapters.each do |chapter| %>
  <tr>
    <td><%= chapter.title %></td>
    <td><%= link_to 'Show', chapter %></td>
    <td><%= link_to 'Edit', edit_chapter_path(chapter) %></td>
    <td><%= link_to 'Destroy', chapter, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New Chapter', new_chapter_path %>

This view has an <h1> at the top, a <table> in the middle to list all of the chapters, and a link (from a link_to) at the bottom.

With what I have stored in the DB locally, my view renders as:

<h1>Listing chapters</h1>

<table>
  <tr>
    <th>Title</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

  <tr>
    <td>Foobar</td>
    <td><a href="/chapters/1">Show</a></td>
    <td><a href="/chapters/1/edit">Edit</a></td>
    <td><a href="/chapters/1" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a></td>
  </tr>
  <tr>
    <td>Asdf</td>
    <td><a href="/chapters/2">Show</a></td>
    <td><a href="/chapters/2/edit">Edit</a></td>
    <td><a href="/chapters/2" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a></td>
  </tr>
  ...
</table>

<br />

<a href="/chapters/new">New Chapter</a>

To us, the novel part of this ERB file is that it is generating multiple <tr>'s with the following:

<% @chapters.each do |chapter| %>
  <tr>
    ...
  </tr>
<% end %>

Notice that the @chapters.each and end lines here are wrapped with <% ... %> and not <%= ... %> because they contain logic that pertains to how the view should be populated, not literal values to be printed into the resulting HTML.

Within the each (which lives inside the <table>), a <tr> will be printed to represent every chapter.

While we're in this file, let's add the chapter body to the <table>:

<table>
  <tr>
    <th>Title</th>
    <th>Body</th>
    ...
  </tr>

<% @chapters.each do |chapter| %>
  <tr>
    <td><%= chapter.title %></td>
    <td><%= chapter.body %></td>
    ...
  </tr>
<% end %>
</table>

Next, let's take a look at the views for new and edit. If you created and edited some chapters of your own from the browser, you've already used the UI that these will generate.

In fact, despite differing headings, links, and prepopulation (in the case of the edit), the forms used in both of these are identical.

The form for new could actually be pre-populated too, but isn't in this case because the chapter instance returned by Chapter.new doesn't have any default values.

So let's see what these two views look like.

### app/views/chapters/new.html.erb

<h1>New chapter</h1>

<%= render 'form' %>

<%= link_to 'Back', chapters_path %>
### app/views/chapters/edit.html.erb

<h1>Editing chapter</h1>

<%= render 'form' %>

<%= link_to 'Show', @chapter %> |
<%= link_to 'Back', chapters_path %>

So we can see exactly why the headings and links are different here from what we already know about ERB, but there is one new piece here. Right in the middle of each of these views, there's this: <%= render 'form' %>.

Like we just observed, the forms for in both views are the same. This is accomplished by saving the view code for the form in a partial and then dropping that in another view using render 'form'. Though our partial is rendered as 'form', it is saved at app/views/chapters/_form.html.erb.

Notice the _ before form in the file name, as this is the way that partials must be saved to file.

But besides the underscore-prefixed file name and the fact that they can be used in other views, partials are the same as any other view.

### app/views/chapters/_form.html.erb ###

<%= form_for(@chapter) do |f| %>
  <% if @chapter.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@chapter.errors.count, "error") %> prohibited this chapter from being saved:</h2>

      <ul>
      <% @chapter.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

There's some error reporting logic at the top, but this is the part we're mostly interested in:

<%= form_for(@chapter) do |f| %>
  ...

  <div class="field">
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

We kick things off with a call to form_for, a helper to generate a form for a given object, in this case @chapter which is passed as an argument. A careful eye will see that everything that follows until end is inside of a block.

Inside this block we can define different <input>'s for the <form> that we want generated by calling methods like text_field on our block variable f.

This will generate a whole slew of HTML. Mine looks like this:

<form accept-charset="UTF-8" action="/chapters" class="new_chapter" id="new_chapter" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="4EJIHYgEaZ2qGKAjr6eJNHa+HM6fH0N+xFrC5x73vqI=" /></div>

  <div class="field">
    <label for="chapter_title">Title</label><br />
    <input id="chapter_title" name="chapter[title]" size="30" type="text" />
  </div>
  <div class="actions">
    <input name="commit" type="submit" value="Create Chapter" />
  </div>
</form>

There's quite a bit going on there, especially at the top. The real takeaway here though is that form_for does a lot of work for us. ...and we should let it.

Looking over the enormous <form> tag that spit out, we'll see this:

<form ... action="/chapters" ... method="post">

And inside, an <input> for the chapter title:

<input ... name="chapter[title]" ... type="text" />

In the <form>, notice that the action and method attributes get the form setup to submit to the create action of our ChaptersController ('chapters#create') by way of POST /chapters.

Oh, and to run the HTML explanations in the ground, we'll recall that <input type='submit'> will POST to the URL stored in the action attribute for that <form> it belongs to. ...using the HTTP request method stored in the <form>'s method attribute.

...as you were.

The <input> is clearly a text input, but the interesting part is the name attribute. In Rails (and other web applications), the name attribute is used to format the way the data, the parameters, are sent to the the server.

To illustrate this, here is the relevant output from rails server as I created a new chapter using this form:

Parameters: {... "chapter"=>{"title"=>"yet another title"}, ...}

These params will eventually make their way into the hash-like params variable we used earlier in the controller, but they start their journey here, defined with name attributes in our generated HTML.

In the case of our chapter title, the <input> defines it with name="chapters[title]", so that will eventually allow us to get at it with params[:chapters][:title] in our controller.

You might have noticed that the parameter hash in the server output has keys that are strings, but I just used symbols.

The reason this works is because params in a Rails controller action is a kind of HashWithIndifferentAccess, which means that you can access the values using the appropriate string or symbol. This means that params[:chapter] and params['chapter'] are equivalent.

If we jump back over to our ChaptersController real quick, we can see in the create action that we access these values to create a new chapter like so:

@chapter = Chapter.new(params[:chapter])

Since params[:chapter] will return a value like {:title => 'yet another chapter'}, it could be represented for this request with literal arguments instead as @chapter = Chapter.new :title => 'yet another chapter'.

Which greatly resembles the stuff we've done in rails console.

Okay, back to _form.html.erb.

While we've got this file open, let's go ahead and add a field for the chapter body to it.

### app/views/chapters/_form.html.erb ###

<%= form_for(@chapter) do |f| %>
  ...

  <div class="field">
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :body %><br />
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Notices

So that's pretty much it for our views, but remember that <%= notice %> from the top of our show view?

### app/views/chapters/show.html.erb ###

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

<p>
  <b>Title:</b>
  <%= @chapter.title %>
</p>


<%= link_to 'Edit', edit_chapter_path(@chapter) %> |
<%= link_to 'Back', chapters_path %>

When we hit the show action straightaway from the browser and inspected the resulting HTML we just saw an empty <p> at the top.

The thing is though, as we've seen playing around with the scaffolded interface, that when creating or editing a record, we also get redirected to this page.

Here's the relevant section from the create action that accomplishes this:

### app/controllers/chapters_controller.rb ###

...

respond_to do |format|
  if @chapter.save
    format.html { redirect_to @chapter, notice: 'Chapter was successfully created.' }
    ...
  end
end

...

Here, redirect_to @chapter will redirect to the show action for that resource, but it also sets a notice to display the user with notice: 'Chapter was successfully created.'.

This notice is then available in the show view using the notice variable and placed into the page with <%= notice %>.

The update action does the exact same thing, but with a different message.

Wrap-up

Well done! We've now made it all the way through the most basic pieces of a Rails application!

At this point, you've now seen everything necessary to understand how a Rails application (or any web application for that matter) works. Way to go.

Now that we've worked through it, let's take a look back at the entire process we just saw.

  1. an HTTP request is received
  2. the Rails application maps the path from the request to a route
  3. this routes the request to a specific controller and action (often represented as [controller]#[action])
  4. the controller action uses the appropriate model to fetch the appropriate data from the database
  5. the controller action takes that model data and places it into the appropriate view to generate the HTTP response body (typically HTML or JSON)
  6. the HTTP response is then sent to the client

Again, this describes a request to a show action.

We can actually understand most of the output from the scaffold generator now too. Reducing it to something more readable, it looks like this:

  active_record
    migrate
    model
    test_unit
  resource_route
    resources :chapters
  scaffold_controller
    controller
    erb (directory + 5 files)
    test_unit
    helper
  assets
    coffee
    scss

We're admittedly ignoring testing for the duration of the book, but we'll be seeing helper and assets next chapter.

So now that we've built something using Rails, let's take a look at where everything goes.

8.4 | Directory Structure

From Rails root, the top level directories and files for our application look like this:

.
├── app
├── config.ru
├── db
├── doc
├── Gemfile
├── Gemfile.lock
├── lib
├── log
├── public
├── Rakefile
├── README.rdoc
├── script
├── test
├── tmp
└── vendor

First, we'll look at each directory.

app

├── app
|   ├── assets
|   |   ├── images
|   |   ├── javascripts
|   |   └── stylesheets
|   ├── controllers
|   ├── helpers
|   ├── mailers
|   ├── models
|   └── views
|       ├── chapters
|       └── layouts
|           └── application.html.erb

We've already looked at controllers, models, and views, but one thing that we have yet to note is that there is a layouts directory under views. Furthermore, there is a single file in this directory: application.html.erb.

### app/views/layouts/application.html.erb ###

<!DOCTYPE html>
<html>
<head>
  <title>Book</title>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

This ERB document is the (default) parent view of the views we rendered before. It has a DOCTYPE declaration at the top (for HTML5) and populates the <head> with the proper CSS and JS as well as some CSRF tag stuff which Rails uses as a security measure.

We'll be looking at these items later on, but the part germane to us at the moment is the only thing that exists inside <body>: <%= yield %>. As you might guess, what is being yielded here is the specific view called by an action.

By default, this view serves as a wrapper for every other view. That is, all rendered views are placed inside the <body> of this view.

Going back to the directory tree for app, we'll see that there are a few other directories that we haven't seen.

helpers contains files that are used to store helper methods for use in corresponding views. These helpers commonly have to do with formatting data for placement in the view so that we don't have to clutter up our views with a bunch of logic. Putting them here also makes it easy for us to reuse these helper methods in other views if we need to.

mailers will hold Rails ActionMailers that can be used to programmatically send and receive emails. We haven't seen any examples of this yet, but this is where they go!

assets contains images, javascripts, and stylesheets. We'll be using those last two quite a bit next chapter. images work pretty much as you'd expect, but the other two involve a little bit of Rails magic.

config

├── config
|   ├── application.rb
|   ├── boot.rb
|   ├── database.yml
|   ├── environment.rb
|   ├── environments
|   |   ├── development.rb
|   |   ├── production.rb
|   |   └── test.rb
|   ├── initializers
|   ├── locales
|   └── routes.rb

config contains our the routes.rb file, as we've seen before, but it has many more files and directories.

There's no need to dive into each of these but we should note that most of these files are things that are run at app startup and impact the way our application will behave. More specifically, we can see each of our environments represented in config/environments.

If you want to add something of your own to be run when the app starts up, the best place to do that is in initializers. Any file in placed in this directory will be executed on startup.

db

├── db
|   ├── development.sqlite3
|   ├── migrate
|   ├── schema.rb
|   └── seeds.rb

We've already seen that db contains our database migrations (in db/migrate), but it also has other purposes.

db also houses our SQLite3 databases, which are stored simply as .sqlite3 files. We can see development.sqlite3 above, but if we were doing testing, we'd have a test.sqlite3 in this directory too.

schema.rb is basically the sum of all the migrations we've run so far:

### db/schema.rb ###

ActiveRecord::Schema.define(:version => 20120816011108) do

  create_table "chapters", :force => true do |t|
    t.string   "title"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
    t.text     "body"
  end

end

This is not a file we want to edit directly (and it says as much at the top), because it is generated automatically by running and rolling back migrations.

It is, however, quite useful to reference if we want to see the details of the columns of a specific table or if we want to see the timestamp of the latest migration we've run, in this case :version => 20120816011108.

We'll be using db/seeds.rb next chapter, so we'll discuss it then.

doc

├── doc

The generated README file that initially resides here informs us:

Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.

This directory will contain said documentation.

lib

├── lib
|   └── tasks

lib/tasks is currently empty, but this is where we can place any Rake tasks that we write ourselves.

We're also supposed to put miscellaneous things that we write ourselves (e.g. modules) in this directory, but since it's a pain to get those to load from here since Rails 3, I just throw that stuff in config/initializers instead.

log

├── log
|   └── development.log

As you might guess from seeing log/development.log, there will also be a test.log and production.log in this directory depending on what environments we've used to run our app.

Let's take a peak at the end of the development log with tail:

$ tail log/development.log 

Started GET "/assets/chapters.js?body=1" for 127.0.0.1 at 2012-08-21 04:18:47 -0400
Served asset /chapters.js - 304 Not Modified (0ms)


Started GET "/assets/application.js?body=1" for 127.0.0.1 at 2012-08-21 04:18:47 -0400
Served asset /application.js - 304 Not Modified (1ms)
Connecting to database specified by database.yml
Connecting to database specified by database.yml
Connecting to database specified by database.yml

We can tell from this that the output from rails server has been sent here, as well as some other things.

Additionally, in most of our Rails files, we can write things to these log files ourselves using logger methods. For example:

logger.info "this will get written to the log"

public

├── public
|   ├── favicon.ico
|   ├── 404.html
|   ├── 422.html
|   ├── 500.html
|   ├── index.html
|   └── robots.txt

This directory is rather special because the static files placed here can be accessed directly from our server over HTTP, with no need for routing.

To prove this, try visiting http://localhost:3000/robots.txt and you'll find that you'll get public/robots.txt sent to your browser straightaway.

favicon.ico will be the 16x16 image that appears in the URL bar in your web browser when we visit our app.

404.html, 422.html, and 500.html all correspond to HTTP status codes ("Not Found", "Unprocessable Entity", and "Internal Server Error") and are served for those respective states.

Let's take a look at the top of index.html in Bash with head:

$ head public/index.html 
<!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails: Welcome aboard</title>
    <style type="text/css" media="screen">
      body {
        margin: 0;
        margin-bottom: 25px;
        padding: 0;
        background-color: #f0f0f0;
      }

After seeing <title>Ruby on Rails: Welcome aboard</title>, it's clear that this is the page we were served when we first visited http://localhost:3000/.

You might remember way, way back I mentioned that a request for http://localhost:3000/ is resolved to http://localhost:3000/index.html. Well, here it is in practice.

A caveat for this is that we don't have a route defined for /. This will change in a bit.

robots.txt is a file that's checked by search engines while they're crawling the web and is used to tell them where not to go within our site.

script

├── script
|   └── rails

As was mentioned in passing before, script/rails is the script that is ultimately run when we use rails in Bash with a Rails project directory.

test

├── test

In case you forgot, you should absolutely looking into testing when your done with this book!

This is where those tests would go if you are using Rails defaults.

Personally, I use RSpec, so I have a spec directory instead.

tmp

├── tmp
|   ├── cache
|   |   ├── assets
|   |   └── sass
|   ├── sessions
|   └── sockets

tmp stands for "temporary". The contents of this folder are mostly things automatically generated by Rails.

I don't know that I've ever done anything with tmp other than blow away everything in it.

vendor

└── vendor
    ├── assets
    |   ├── javascripts
    |   └── stylesheets
    └── plugins

Third-party code like Gems and JavaScript libraries can end up here.

The Files of Rails Root

├── config.ru
├── Gemfile
├── Gemfile.lock
├── README.rdoc
├── Rakefile

config.ru is a "rackup" file, denoted by the .ru extension. The comment at the beginning of the file says all we really need to know:

# This file is used by Rack-based servers to start the application.

Gemfile is what we've already used to add new gems to our applications, like thin and pg.

Gemfile.lock is generated when we run bundle install and keeps track of the versions of all the gems we have installed for the current bundle. Assuming we have this file in source control (as we should), if we ever get any problems from using newer versions of gems, we can simply build our bundle over using this file from our last known, error-free commit.

README.rdoc is exactly what it sounds like. More commonly (especially on GitHub) you'll instead see a README.md file.

.md stands for "markdown" which GitHub supports quite thoroughly, not only for their repo READMEs but for their comments as well.

Rakefile tells rake how to work inside of our application.

Without it, rake doesn't know what to do with itself:

$ mv Rakefile .Rakefile
$ rake routes
rake aborted!
No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb)

And that concludes the file structure tour. All that's left now is to finish our project, so let's get on that!