Face Blog - Models and Validation

Now that you have everything installed, you’re ready to rock n roll. It’s time to create your first rails application. You’re going to create a new social networking site called Face Blog.

Creating a Rails App

cd src/1 # From the jbug root directory.  We'll work from here.

First thing you need to do is create a new rails application. Well that’s pretty easy.

rails new face_blog

Notice the file structure. Every rails app looks the same. This makes it easy to quickly get involved in other rails projects, since you’ll already know your way around.

The main areas you’ll be working in today are:

app/       # This contains all your MVC files
config/    # Used to configure your app
db/        # Where migrations and schema lives

Adding gems

First thing we’re going to add to our site is a User. We want to allow the user to login, signup and all that jazz. But of course we’re not going to write all that ourselves. We’ll use a library to do the grunt work for us.

We’re going to add “devise” (an authentication gem for rails) to our application, as well as a few extra libraries that we’ll need later.

All the libraries your rails application depends on are specified in your applicatons Gemfile (found in your applicaitons root directory). Let’s add in ‘devise’ and a few of other libs such as a javascript runtime, openssl and jdbc adapter for sqlite3.

Open up your applications Gemfile and add the following under where is says: gem “rails”, “3.2.x”

gem 'devise'
gem 'execjs'
gem 'therubyrhino'
gem 'jruby-openssl'
gem 'activerecord-jdbcsqlite3-adapter'

Notice the convention here.

The gem followed by name on the left followed by the version.

gem 'rails', '3.2.6'

This specifies we want to include version 3.2.6 of rails. Each gemfile has a source:

source 'http://rubygems.org'

This tells the bundler (the component responsible for retreiving the gems) where they are located.

Another interesting thing in our Gemfile is the group block. We can include gems specifically for different groups for example:

group: test do 
  gem 'rspec'
end

This will include the rspec gem (a testing library) only in our test environment.

Run bundler to pull the dependecies into our gemset. Make sure you’re in your application’s root directory and run:

bundle install

Note: A gemset is a feature of rvm. It allows us to create groups of gems (a level above those specified in our Gemfile) that are contained from other gems to prevent things like version conflicts. It’s reccommended that you use one getset per application environment.

So Back to devise; We need to do a little setup. From you’re terminal run the following (from you’re application’s root directory)

rails generate devise:install
rails generate devise:views

Note: devise:install and devise:views are rails generators. Generators are scripts that add some setup to your application. Rails comes as default with a number of generators that you can use for creating things like controllers, models and migrations. We’ll use these later.

Testing our app

Before we continue, let’s make sure we have the correct dependencies and that we can deploy our rails app on TorqueBox. Start TorqueBox and deploy your applicaton. If all goes well you should be able to see the rails landing page. For information on how to start TorqueBox and to deploy your app check out section 2. Running TorqueBox. Be sure to return here when your done.

Rails Console

For the next section we won’t be needing to test things in TorqueBox, we’ll use the rails console. The rails console is a ruby irb (Itegrated Ruby Shell) with your full rails application enviornment loaded. It’s ideal for testing models, validation and just for trying things out. To start the rails console type:

rails c # from you applicaton root directory

You can now issue ruby commands. Just try:

1 + 1

If you make changes to your model, database, controllers etc… You’ll need to reload the enviroment. To do that issue the reload! command:

reload!

To close the rails console type:

quit

Models and Migrations

So we started off by saying we were going to add a user. Let’s get to the chase.

To create our user model and migration we’ll use a model generator. This will create our model a migration file to update the database and a few other things used for testing. If your curious you can check to see what generators are available in your app:

rails generate

To create our user model we’ll use the devise model generator, here we’ve specified that we want to create a model call User and that we want it to have 2 attributes, name and dob.

rails generate devise User name:string dob:date

We’ve not come across migrations yet.

Migrations are scripts that update your database from one state to another. If you take a look at the migration we just created (under db/migrate) you’ll see that the migration specifies that we want to create a new table and add some table fields. (The extra fields; email, password etc… are added by devise and are will be used later for authentication))

We might create another migration later that adds extra fields to the table or deletes the table. The key thing to remember is that a migration will evolve the database it is not a big bang approach.

Notice that the migration is timestamped this is how Rails knows the order to run them in.

Next, take a look at db/schema.rb. Each time a migration is run, the schema is updated to represent the current database state. The timestamp up where the schema is defined represents the last migration that was run. If you add in extra migrations, rails will know to start from the timestamp given in the schema.

So, now that we’ve added some migrations we’ll create the applications databases and run our migration.

rake db:create:all # Creates databases
rake db:migrate    # Migrates the current rails env database: development

Next we’ll make the our dob and name attributes pubic (This is so we can mass-assign them later in our controller). We do this by setting the attr_accessible method.

Open up the model app/models/user.rb and add in :name and :dob to the attr_accessible method:

attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :dob

Validations

You can now test out your model in the rails console.

rails c

Lets create a new user from the rails console.

me = User.new(:name => "Martyn", :dob => "11/22/1984")

What happens when you try to save me to the database.

me.save!

You should have received a validation exception and probably a stack trace.

This happens because devise has already added some extra validation to our model. We must enter a unique email and password and password_confirmation (which must match) Let’s try again.

me = User.new(:name => "Martyn", :dob => "11/22/1984", :email => "mtaylor@redhat.com", :password => "password", :password_confirmation => "password")
me.save!

Voila it works. Congratulations you’ve just created your first rails model and saved an object to the database. :D

NOTE:

Through out this section your going to create many users. Devise has a uniqueness validation on email address. So you’ll likely get complaints from Devise should you try and create another user with an address that is already taken. You can easily delete users from the rails console (rails c):

# Delete a single user
me.destroy

# Delete All Users
User.all.each { |u| u.destroy }

Now we’ve seen devise validations in action, its time to add our own. Face Blog is for over 18s only and user must supply a name. Let’s start by adding validation to make sure name is not empty. Open up the user model, add in name validation.

validates :name, :presence => true, :length => { :minimum => 2 }

This makes sure that a user supplies a name and its length greater than or equal to 2

Now time for checking the age. We could use the rails helper methods for checking the age. But instead we’re going to create a custom method to stop underage users signing up.

validates :dob, :presence => true
validate :must_be_an_adult

def must_be_an_adult
  if (Time.now - 18.years) < dob
    errors.add(:age, "must be over 18")
  end
end

Reload open up a new rails console “rails c” or run reload! (This reloads your environement) from your existing IRB session:

Try it out to see if its working.

User.create!(:email => "mtaylor@redhat.com", :password => "password", :password_confirmation => "password", :dob => "01/01/2010", :name => "")

You should receive another validation exception informing us that the name cannot be blank and the users age must be over 18.

Associations

Now that you’ve grasped validations it’s time to move on to associations. Associations in rails are simply relationships between models.

Face Blog allows users to add friends. To do this wel’ll need an extra model, we’ll call it friendship. This will be used to store mappings between users. We’ll setup model assoications to acheive the ERD show below:

To start we need to create the extra friendship model. We’ll use a generator to do this, run the following from your terminal in your application root directory:

rails generate model Friendship user_id:integer friend_id:string
rake db:migrate

Note the naming convention here. When we setup associations in rails, ActiveRecord automatically looks for a foreign key named <association_name>_id. It’s possible to override this, but we’ll stick to convention for now to make it easy.

Next we need to add in the association into the models.

In the friendship model we add two associations

belongs_to :user
belongs_to :friend, :class_name => "User"

these associations link up the two ids we store to User objects. For each friendship we can now get the User (the owner of the friendship) and the Friend (Another User).

Now lets do the same on the User side.

has_many :friendships
has_many :friends, :through => :friendships

The last association is more of a convenience method. Really we want to deal with friends not with friendships, ActiveRecord will look at the friendship Model for an association called :friend which we defined previously, and retreive the User with that ID.

Now time to test it all out. Reload your rails environment again: ‘reload!’ and create some users and friendships.

# Delete all users (To prevent any conflicts)
User.all.each { |u| u.destroy }

# User 1
martyn = User.create!(:email => "mtaylor@redhat.com", :password => "password", :password_confirmation => "password", :name => "martyn", :dob => "11/22/1984")

# User 2
dave = User.create!(:email => "dave@redhat.com", :password => "password", :password_confirmation => "password", :name => "Dave", :dob => "01/01/1950")

# Add dave as a friend
martyn.friends << dave
martyn.save!

# Check the relation
martyn.friends

You might have noticed that dave still has no friends. This is becuase we only set up the association in one direction. We could add the inverse assoications to the user model, which would solve this issue. But for the sake of simplicity we’ll simply add an extra friendship entry.

# Add Martyn as Daves friend
dave.friends << martyn
dave.save!

Overview

There you have it. You’ve successfully managed to create new models, migrations add validation and setup associations. All in the space of a few minutes. Next we’ll start building up the Controller and View side of our applicaton. We’re going to need a ruby server running to test this. If you haven’t already, check out the Running TorqueBox section. If your having trouble with TorqueBox don’t worry you can just use the default ruby server for testing purposes. To start it:

rails s