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] 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
rails
gem 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
Gemfile
to pick a JavaScript interpreter (I recommend The Ruby Racer) then update yourGemfile.lock
file by running thebundle
command.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 generate
israils 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-fixture
option 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.rb
then:rake db:migrate
-
Add validation and authentication code by editing the following files.
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 (or diff against the previous branch).
-
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
Gemfile
to add new dependencies: themoney
andfactory_girl_rails
gems. Then use thebundle
command to update theGemfile.lock
file.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 (or diff against the previous branch).
-
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
-
Add session logic (login, logout) by editing the following files.
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
-
Test session management.
Generate a new integration test:
rails g integration_test login_flow
Edit the following files:
test/functional/sessions_controller_test.rb
test/integration/login_flow_test.rb
Then run the tests:
rake test
-
Create a user record for yourself.
Start the rails console and add a user record to the database. The console allows you to interactively type in Ruby code:
rails console User.create!(:first_name => 'John', :last_name => 'Doe', :email => 'john@doe.com', :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] localhost.
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 (or diff against the previous branch).
-
Add the controller logic and views to create and edit cars.
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
-
Play with the new interface.
Start the rails server:
rails server
Try the following URLs:
-
Create a controller and the interface for working with refuels.
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
-
Show information about the last refuel on the cars index.
Add a
scope
to 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
-
Improve the look and feel by adding some CSS and HTML changes.
Edit the following files:
app/views/layouts/application.html.erb
app/assets/stylesheets/basic.css.scss
app/assets/stylesheets/forms.css.scss
-
Play with the application.
Start the rails server and open [http://localhost:3000/] cars.
-
If you are creating a car or refuel record and omit a required field, the model validations will prevent the record from being saved to the database. In prior versions of Rails a list of error messages would be shown above the form.
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.
-
Instead of implementing your own session management and authentication logic you may want to look at one of these plug-ins for Rails:
-
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
users
controller to allow a user to create an account. -
Write a
passwords
controller 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_timeout
user attribute toTime.now + 5.seconds
and don't let the user log in whilelogin_timeout
is in the future. Each time the user tries to log in with the wrong password increase the number of seconds in the future thelogin_timeout
is set for. Display thelogin_timeout
in the login form so the user knows what's going on. Tip: it may help to have afailed_logins
counter 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.