Self-guided Ruby on Rails 3.1 Tutorial
This is a small application using Ruby on Rails 3.1 to demonstrate how a new application might be bootstrapped and features added over time. It's a self-guided tour, you should use this guide to follow along with the commits and branches. Even better, you should try to replicate each step on your own using this application as a guide.
Make sure you open each referenced file in your text editor of choice. As new features are introduced comments in the source code provide guidance as to why they are being used.
This example application is brought to you by Peter Jones and Devalot. For more information about this application please read this article.
This is very simple application where you register your car and then record basic information each time you go to the gas station and refuel. It then calculates some basic information like miles per gallon (my apologies to the rest of the world that uses the much preferred metric system).
Follow along with each step trying to recreate the changes in your own application. Use the features of git to help you see the changes in each branch and for each file. If you are not comfortable with git you can use the browser interface on Github.
If you don't understand something Google is your friend. You can also open a ticket or post a comment on Github.
Before you start you should have a working installation of Ruby. Versions 1.8.7 and 1.9.3 should both work. You should also have SQLite3 installed.
If you're going to jump right in and run the application as it is right now, you can:
git clone git://github.com/devalot/ror-example.git cd ror-example bundle install rake db:migrate rails server
Install the
railsgem and create a new Ruby on Rails application.
gem install rails rails new example cd example
Feel free to use a name other than "example" for your application.
Remove some of the default files that we won't be using.
rm app/assets/images/rails.png rm public/index.html rm public/favicon.ico
Edit the
Gemfileto pick a JavaScript interpreter (I recommend The Ruby Racer) then update your
Gemfile.lockfile by running the
bundlecommand.
bundle install
Optionally create a new Git repository for this rails application.
git init git add . git ci -m "Initial commit"
The very first thing we'll want to do is create a model for users and a database table for users. We'll also need some basic authentication code in place to store a user's password securely.
To see what the application looks like at the end of this section you can use the 01-user-model branch. To see a diff for the changes in this section use commit 1e32158.
Use the rails generator to create a user model. A shortcut for
rails generateis
rails g.
rails g model user
Well be using FactoryGirl instead of fixtures, so remove the fixture file that was created. We could have also given the
--no-fixtureoption to the generator to not generate the fixture in the first place.
rm test/fixtures/users.yml
The model generator also created a database migration that needs to be edited so we can properly set up the users table in the database.
Edit
db/migrate/20111102182704_create_users.rbthen:
rake db:migrate
app/models/user.rb
test/unit/user_test.rb
Then run the tests.
rake test
Next we're going to need models and database tables for cars and refuels.
To see what the application looks like at the end of this section you can use the 02-car-refuel branch. To see a diff for the changes in this section use commit 8032839.
Create two more model files for cars and refuels.
rails g model car --no-fixture rails g model refuel --no-fixture
Edit the migrations to set up the cars and refuels database tables.
db/migrate/20111102192932_create_cars.rb
db/migrate/20111102210426_create_refuels.rb
Then migrate the database:
rake db:migrate
Edit the
Gemfileto add new dependencies: the
moneyand
factory_girl_railsgems. Then use the
bundlecommand to update the
Gemfile.lockfile.
bundle install
Add the appropriate model associations and create the logic for calculating miles per gallon. Edit the following files.
app/models/user.rb
app/models/car.rb
app/models/refuel.rb
Create a file to hold the testing factories (a simple way to build model objects) and then add some testing logic for the calculations in the refuel model. Edit the following files.
test/factories.rb
test/unit/refuel_test.rb
Make sure all the tests are passing.
rake test
Now we can add the files necessary to play with the application in a web browser. We're going to add the ability to log in and log out of the application.
To see what the application looks like at the end of this section you can use the 03-sessions branch. To see a diff for the changes in this section use commit 2ba4d36.
Generate two controllers.
rails g controller cars rails g controller sessions
Remove files we don't need.
rm app/assets/javascripts/cars.js.coffee rm app/assets/stylesheets/cars.css.scss rm app/assets/javascripts/sessions.js.coffee rm app/assets/stylesheets/sessions.css.scss
Add routes and authentication helpers by editing the following files.
config/routes.rb
app/controllers/application_controller.rb
app/controllers/sessions_controller.rb
app/views/sessions/new.html.erb
Add minimum logic to the cars controller.
Edit the following files:
* `app/controllers/cars_controller.rb` * `app/views/cars/index.html.erb`
Generate a new integration test:
rails g integration_test login_flowEdit the following files:
test/functional/sessions_controller_test.rb
test/integration/login_flow_test.rb
Then run the tests:
rake test
Start the rails console and add a user record to the database. The console allows you to interactively type in Ruby code:
rails consoleUser.create!(:first_name => 'John', :last_name => 'Doe', :email => '[email protected]', :password => 'foobar', :password_confirmation => 'foobar')
Now see if you can log in, keeping in mind that you can't yet add a new car. Start the rails server then open http://localhost:3000.
rails server
Finally, we're going to add the ability to create cars and refuels in the browser.
To see what the application looks like at the end of this section you can use the 04-create-refuels branch. To see a diff for the changes in this section use commit da7d7de.
Edit the following files:
app/controllers/cars_controller.rb
app/views/cars/new.html.erb
app/views/cars/edit.html.erb
app/views/cars/index.html.erb
Start the rails server:
rails server
Try the following URLs:
Create the controller:
rails g controller refuels rm app/assets/javascripts/refuels.js.coffee rm app/assets/stylesheets/refuels.css.scss
Edit the following files:
config/routes.rb
app/controllers/refuels_controller.rb
app/views/refuels/index.html.erb
app/views/refuels/new.html.erb
app/views/refuels/_form.html.erb
app/views/refuels/edit.html.erb
app/views/refuels/show.html.erb
Add a
scopeto keep logic in the model. Also add some methods to format the MPG attribute and calculate a cost per mile. Edit the following file:
app/models/refuel.rb
Add some additional details to the cars index to show MPG and cost per mile for the most recent refuel. Edit the following file:
app/views/cars/index.html.erb
Edit the following files:
app/views/layouts/application.html.erb
app/assets/stylesheets/basic.css.scss
app/assets/stylesheets/forms.css.scss
Start the rails server and open http://localhost:3000/.
That feature was removed in Rails 3 in order to make it easier to translate your application into multiple languages. This means that you must generate your own user error messages.
You can also install the dynamic_form plug-in to get these helper methods back into Rails 3 until you are ready to write them yourself.
If you edit an existing refuel object and change the odometer or gallons attributes, the refuel object directly following the one you edited will have wrong values for distance and mpg. Update the refuel model to recalculate these values when this happens. Start by writing a test that fails. This will also happen if you delete a refuel.
Write a
userscontroller to allow a user to create an account.
Write a
passwordscontroller to allow a user to change their password. How would a user reset their password if they forgot it?
If a user enters the wrong password while logging in, set a
login_timeoutuser attribute to
Time.now + 5.secondsand don't let the user log in while
login_timeoutis in the future. Each time the user tries to log in with the wrong password increase the number of seconds in the future the
login_timeoutis set for. Display the
login_timeoutin the login form so the user knows what's going on. Tip: it may help to have a
failed_loginscounter in the users table. Don't forget to reset it to 0 when the user successfully logs in.
Explore using Ajax to create cars and refuels so the user doesn't have to bounce around the application for each activity.