Railsbridge Workshop

Contents

Other Pages

Site List

Curriculum

Build and deploy a web application

We will build a web application for people to create topics and vote on them. Ultimately, we'll have registration and authentication and a variety of other features. Today we'll focus on building the core features of topics and votes.

Here is the UI design for the application:

Suggestotron_topics_index.jpg

Let's build a web application

IF you don't have curl installed then click on the link, download the txt file, save it locally and then instead of the above command do the following command:

rails new suggestotron -m workshop_template.txt

Everything you need for your application is now in the suggestotron folder. If you decide you don't like it, just delete it and start over with the rails new command.

The -T option (T for Test) is a shortcut to tell the rails command to not use Test::Unit because we will be using RSpec instead.
The -m option (m for teMplate) is a shortcut for a few commands (listed [http://gist.github.com/609269.txt here]). Mostly it sets up cucumber features and installs the gems you need to run them.

Normally, you probably wouldn't use a template. Eventually though you might create your own template with your frequently used options.

Next step: Go to your new folder:

cd suggestotron

To see what the rails command created for you, type the following:

ls

(That's a lower-case L, for "list.")

rails new created the following files and subdirectories within it:

File/Folder Purpose
Gemfile This file lists the gems that bundler will install in your project.
Gemfile.lock This file lists the gems that were installed for your project.
README This is a brief instruction manual for your application.
Rakefile This file contains batch jobs that can be run from the terminal.
app/ Contains the controllers, models, and views for your application. You will do most of your work here.
config/ Configure your application’s runtime rules, routes, database, and more.
config.ru This file makes our app rack-friendly (.ru stands for rackup).
db/ Shows your current database schema, as well as the database migrations.
doc/ You would add documentation for your application here
features/ Added by the template. This is from cucumber, which is not part of core Rails
lib/ Extended modules for your application (not covered today)
log/ Application log files
public/ The only folder seen to the world as-is. This is where your images, JavaScript, stylesheets (CSS), and other static files go
script/ Scripts provided by Rails to do recurring tasks. We'll use some today
spec/ Unit tests, fixtures, and other test apparatus
tmp/ Temporary files
vendor/ A place for third-party code

Set up your web application

If you haven't already, change to the suggestotron directory by typing:

cd suggestotron

Run the web app server:

rails server

Windows 7 Users:
If you get an Invalid gemspec in c:/...mingw32.gemspec]: invalid date format in specification: "2011-08-20 00:00:00.000000000z" error:

Point your web browser to [http://localhost:3000 http://localhost:3000]. See your web app actually there!

Make it your own

If you don't see a list of files and folders to the left, then go to:

Edit index page

The page you are seeing at http://localhost:3000 is a static page, located at public/index.html.

Make a change, save, and reload your browser to see it!

Awesome! Let's ship it!

From your new "suggestotron" directory, create a local git repository:

git init

This tells git that we want to start tracking the changes to this directory.

A little note about gitignore

Whenever we commit a project, git tracks every file by default. There are, however, files that we'd rather leave untracked (or, ignored).
There is a hidden file in your app called "gitignore" that has a period as its first character in its filename to hide it from your normal directory view (this is why you didn't see it if you looked at your directory list earlier)
The entries in the "gitignore" file tell git what to avoid when tracking the changes of our project files.

If you open the ".gitignore" file, you'll see this:

.bundle
db/*.sqlite3
log/*.log
tmp/**/*

Making the first commit

After we've done that, we can proceed with our first commit by entering the following lines into the terminal:

git add .
git commit -m "basic web application"

This saves a snapshot of the application to git. Let's check to make sure that everything was committed.


git status git log

git status tells you whether you've made changes that haven't been saved in git. Currently it should show you something like this:

# On branch master nothing to commit (working directory clean)

git log shows you a history of all your commits. You should see one entry - the commit you just made.

To exit git log, hit the letter 'q'.

Once you've checked that, it's time to deploy to Heroku!

heroku create
git push heroku master

Notice the URL that heroku reports after you typed "heroku create." Type this URL in your browser to see your application on the web. If you don't want to do that, the command heroku open does this for you by opening the browser.

A Closer Look at the Features

group :production do
  gem 'therubyracer-heroku', '0.8.1.pre3'
  gem 'pg'
end

bundle install --without production
git add .
git commit -m "heroku postgresql workaround"
git push heroku master

     bundle install
     rails generate cucumber:install --rspec --capybara

In the /features directory are several files that end in .feature. These are cucumber features that describe the application we're building.

You can find the first piece of the app that we'll build in features/1_topics.feature:

Feature: Topics
  In order to see a list of potential topics for meetings
  people need to be able to create and edit them

  Scenario: Getting to the new topic page
    When I go to the topics page
    And I follow "New Topic"
    Then I should see a "Create" button

It's got several "scenarios" in the file. You can run all the scenarios in topics.feature like this:

rake cucumber FEATURE=features/1_topics.feature

NOTE:

Then re-run "bundle install" and "rails generate cucumber:install --rspec --capybara" (select "a" for overwrite all").

=Once you've run it=

Once you are able to run it, the first thing you'll notice is that it fails! That's good, because we haven't written any code yet.

These features are tests as well as documentation. The typical Rails workflow is:

This is the workflow we'll be using today.

1_topics.feature relies on some basic elements of a web app, which is what we'll build first. As we get features to pass, we'll look further at the features definitions to see what needs to be built.

First Feature: Adding topics

We can look through the features and screen shots and see how a topic is defined and how people expect to interact with it. We will use rails "scaffolding" to generate some pages and code.

Scaffolding

It contains Ruby code to set up the database table. Migrations can also be used for modifying tables (add/remove/rename columns) and even modifying data.

Now let's look at the feature we created by running the server locally.

Congratulations! You have built a web application that works with a relational database.

A Quick Look at Your Database

You can access the database directly on your local machine. For this class we’re using SQLite, and we've installed SQLite Manager, a GUI tool that lets you inspect the database. To open it, open Firefox, then select "Tools -> SQLite Manager."

Click the open folder icon Folder.jpg  or choose Database -> Connect Database to open suggestotron/db/development.sqlite3

Windows Users: You may have to change the file type selection field to "All Files" to be able to see files with the sqlite3 file extension.

Sqllit.jpg

In SQLite, you can choose “Browse & Search” to interactively explore the database or “Execute SQL” to type SQL commands.

You can also access the database through the command line:

rails dbconsole
Common SQL Commands
sqlite MySql PosgreSQL
list tables in current db .tables show tables; \d
show SQL for table create list columns .schema .schema topics show create table topics; describe topics; \d topics
exit command line tool .quit exit \q
show all rows in table colspan="3" | select * from topics;
show number of rows colspan="3" | select count(*) from topics;
show matching record colspan="3" | select * from topic where title = "My Topic";

Deploy Your Application

Don’t forget, "commit early, deploy often." Here's how:

git add .
git commit -m "topic crud"
git push heroku master
heroku rake db:migrate

If you run into error, uninitialized constant Rake::DSL then add following to your Rakefile:

require 'rake/dsl_definition'
require 'rake'

Congratulations! You have built and deployed a web application that works with a relational database.

Rails implements a very specific notion of the Model-View-Controller pattern, which guides how you build a web application.

Model

View

Controller

Mvc.jpg

Mvc-stickman.png

When you executed the rails generate scaffold command, Rails generated files that implement a model, some views, and a controller for topics.

The Model

Five Views

The Controller

A closer look

Rails allows you to easily invoke an interactive console with all of the Rails libraries and your application code loaded:

    rails console

Let's add in some logging so that we can see what is happening in the database:

ActiveRecord::Base.logger = Logger.new(STDOUT)

Let’s open the console and look at the model that is defined here: app/models/topic.rb

>> t = Topic.new
=> #
>> t.title = "My topic"
=> "My topic"
>> t.description = "this is really cool"
=> "this is really cool"
>> t.save

Notice that the Topic class has title and description attributes which you did not need to explicitly declare in the class. This is handled by ActiveRecord which implements ORM (Object Relational Mapping) in Rails.

Routes

Rails routes control how URLs map to code. We can use rake routes to list the relationships between routes and controllers.

$ rake routes
    topics GET    /topics(.:format)          {:action=>"index", :controller=>"topics"}
    topics POST   /topics(.:format)          {:action=>"create", :controller=>"topics"}
 new_topic GET    /topics/new(.:format)      {:action=>"new", :controller=>"topics"}
edit_topic GET    /topics/:id/edit(.:format) {:action=>"edit", :controller=>"topics"}
     topic GET    /topics/:id(.:format)      {:action=>"show", :controller=>"topics"}
     topic PUT    /topics/:id(.:format)      {:action=>"update", :controller=>"topics"}
     topic DELETE /topics/:id(.:format)      {:action=>"destroy", :controller=>"topics"}

Each method in the controller will take an HTTP request, usually find some data in the database (via an ActiveRecord model) and render a view or redirect to another action.

See Workshop_Diagrams to help trace the connections between HTTP, REST, routes, controllers, and databases.

How to explore your routes

Open up your rails console:

rails console

Now you can have a look at the paths that are available in your app. Let's try looking at one of the topics routes we just generated.

app.topics_path => "/topics" app.topics_url => "http://www.example.com/topics%22

Remapping /

You can specify what Rails should route "/" to with the root method in routes.rb. You should put the root route near the end of the file, but before the final "end".

root :to => 'topics#index'

After adding the root route, your routes.rb file should look like this:

Suggestotron::Application.routes.draw do

resources :topics
root :to => 'topics#index'

end

You also need to delete the index.html file for the root route to work.

git rm public/index.html

Next feature: creating a topic

Let's run the feature again and see what the next scenario is.

rake cucumber FEATURE=features/1_topics.feature

  Scenario: Creating a topic
    Given I go to the topics page
    And I follow "New Topic"
    When I fill in "Title" with "Rails Fixtures"
    And I fill in "Description" with "Introduce how to add test data with fixtures."
    And I press "Create"
    Then I should see "Rails Fixtures"
    And I should be on the topics page

Run the server (rails server), look at the app ([http://localhost:3000/topics/ http://localhost:3000/topics]), and see how the scaffold template differs from the desired application as we've described it above using cucumber. What we want is the application to show the list of topics after the user creates a topic by completing the form. However, the scaffold displays instead a page showing only the individual topic the user just created.

Controller: adjusting the flow of your application

We looked at the scaffold-generated code a little earlier. To change the behavior and make the feature act as desired, we will look more closely now at the controller, which controls the general flow of your application; for instance, which page is displayed when the user clicks a link or a button.

Commit & Push

Congratulations! This is definitely a checkpoint. Time to commit to git and push your changes out to Heroku.

git add . git commit -m "ZOMG first feature passes!!1!!11" git push heroku master

(Run ‘heroku rake db:migrate --app ’ to bring over changes in the migration files under Feature 1.)

Next feature: the Topics page

Note that for this next set of feature scenarios we have a "Background" set of steps which will be executed before each scenario in the file. Since they depend on behavior that already works, they're rendered in green (pass).

  Scenario: Viewing a topic detail page
    When I go to the topics page
    And I follow "Rails Fixtures"
    Then I should see "Introduce how to add test data with fixtures."
    And I should not see "New Topic"

Commit & Push

Another checkpoint! Time to commit to git and push your changes out to Heroku.

git add . git commit -m "Topic titles are now links. for srs." git push heroku master

bundle exec rake assets:precompile

Be sure to commit your changes and push your changes to Heroku

Next feature: allow voting on a topic

Feature: Votes
  In order to determine which talk to give
  people need to be able to vote for the ones they like
  
  Background: Make sure that we have a topic
    Given I go to the topics page
    And I follow "New Topic"
    And I fill in "Title" with "Rails Fixtures"
    And I fill in "Description" with "Introduce how to add test data with fixtures."
    And I press "Create"
    
  Scenario: viewing votes already cast
    When I go to the topics page
    Then I should see "0 votes"
    
  Scenario: voting on a topic
    When I go to the topics page
    And I follow "+1"
    Then I should see "1 vote"

rake cucumber FEATURE=features/3_votes.feature

How will we build this feature?

Rails associations

* Topic has_many :votes
* Vote belongs_to :topic

Rails-associations.jpg

Add votes

We will use the resource generation script to create a model and controller (no views):

rails generate resource vote topic_id:integer

And then we migrate

rake db:migrate

The script creates files with:

Add code to to your models to create the associations:
*/app/models/topic.rb

 class Topic 



*/app/models/vote.rb

 class Vote 


Check it out in rails console:

>> t = Topic.new(:title => "My Topic")
=> #<Topic id: nil, title: "My Topic"), description: nil, created_at: nil, updated_at: nil>
>> t.votes
=> []
>> t.votes.build
=> #<Vote id: nil, topic_id: nil, created_at: nil, updated_at: nil>
>> t.votes
=> [#<Vote id: nil, topic_id: nil, created_at: nil, updated_at: nil>]
>> t.save
=> true
>> t.votes
=> [#<Vote id: 2, topic_id: 2, created_at: "2010-02-22 01:42:27", updated_at: "2010-02-22 01:42:27">]

Now you can use it in your view (/app/views/topics/index.html.erb):

<td><%= pluralize(topic.votes.length, "vote") %></td>

Allow people to vote

It's good to do one bit at a time and let the test failures drive what you do next.

Check rake routes for figuring out the pathTODO: diagram or screenshot of where this info is on the rake output, and edit your view (/app/views/topics/index.html.erb):

<%= link_to '+1', votes_path(:topic_id => topic.id), :method => :post %>

Now we need to create the controller action. Open the Votes controller (/app/controllers/votes_controller.rb) to add the create action:

class VotesController 


Add flash notice to app/views/layouts/application.html.erb

What Next?

Resources and Next Steps

http://bit.ly/ruby-resources

Railsbridge Docs

Source: https://github.com/railsbridge/docs