Beginners Guide: Starting With The Model
Posted by Tom Rossi on August 14, 2006Comments (12)
Ruby on Rails, Tutorials
Beginners Guide:
1. Getting Ruby on Rails Running on Windows
2. Introduction to the MVC architecture.
3. Starting with the Model
Starting With The Model
In this tutorial, I'd like to look at the Model, or building a domain model. Maybe I am a total geek, but I really enjoy this part. We will look at modeling our classes and data, building our database, and some really cool interaction with our model using interactive Ruby.The Application
So, I think the best way to approach these tutorials moving forward is to have an application that we are building together. I just happen to need an application for my church (RCCJAX). We really need a little contact management solution to track people (members and volunteers), their relationships to each other, and groups. This is what I will be using, but feel free to work on your very own!
The Classes
I am doing my best to stick by the Rails approach and being an "agile" programmer. One of the implications is that we don't spend time on documentation that looks pretty and never gets used. So rather than busting out the Visio and building a Class Diagram and Entity Relationship Diagram, I'm going to use a simple a little sketch:
You can see my thinking of the entities or classes that will be interacting in the application. We will have People, Relationships, and Groups. People belong to groups and also have relationships with other people (children, parents, friends, etc.) We will start with modeling the class Person (class names are in the singular form as we'll see later).
Our Model And The Database
Okay, this is totally awesome. Rails allows us to overlay our model with our database using something called ActiveRecord. Let me try to break it down. We've already said that we will have Person objects within our application. For those of you not as familiar with object-oriented thinking: objects are just instances of classes. Where do you think we will be storing information about them? This information represents the attributes of the objects and are of course stored in a database. Isn't it logical to expect that for many of our objects there is a corresponding table to store their attributes? Isn't it also logical that the attributes would be fields in those tables? For example, in the people table we will have things like first name, last name, home phone, etc. So, within Rails our models can have database tables underneath them to store their data. Here come the conventions!
Rails will expect the model to be singular and the table name to be the plural of the model.
So for our application, Rails will expect for the Person model (or class or object or whatever you feel most comfortable saying) that their will be a table called people. Likewise, for the Relationship model we will have a table called relationships and the Group model a table called groups. This can put you out a bit since you wouldn't expect a framework to tell you what to name your tables. Remember all of these are just conventions. Live by them and your life will be free, easy, and full of joy (insert birds chirping). Override the conventions and your going to spend a lot of time doing excess configuration and waive bye bye to saving time building your application (insert ominous drumming). Yes, sometimes you have to override the conventions, but hopefully few and far between.
Generating Our Application
We did this in our first tutorial just to test out our windows installation of Rails, but now lets create our new application. First go to the folder where you want to store your rails applications. I put mine in C:\Documents and Settings\Tom\My Documents\My Rails Projects>.
We are going to "generate" our application by using the following command:
- rails appname
This will create all sorts of files that we will be using throughout our development. Remember generators are used extensively with Rails and are intended to save us time by setting up the file skeletons for us. At first I tried not to use them, but that is just nuts.
My Rails Projects>rails rccjax
create
create app/controllers
create app/helpers
...on and on...
create log/test.log
So now we have generated our application, in my case rccjax.
Our First Model
Now we have our application and want to generate our first model. To do this we will use the following command:
- ruby script/generate model ModelName
This is basically calling the ruby executable to run the generate script stored in the script relative path with the option model and the name of the class.
For our rccjax application, lets create our Person model first:
My Rails Projectsrccjax>ruby script generate model Person
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/person.rb
create test/unit/person_test.rb
create test/fixtures/people.yml
create db/migrate
create db/migrate/001_create_people.rb
Notice we followed convention and named our model in the singular form person. Rails is smart enough to now expect the plural form people in the underlying database.
Again, we see the generator created a lot of files. If you are like me, your a little freaked out, but don't worry you'll learn all of these files before too long. The important one for us right now is the actual model file:
app/models/person.rb
Go ahead and open this file using your favorite text editor. I recommend Notepad++ when you just want a simple text editor. I would steer clear of an IDE just yet, lets get some of this under our belt the hard way so we can appreciate them more.
app/models/person.rb:
- class Person <ActiveRecord::Base
- end
Believe it or not, you don't need much else! That tiny bit of code tells Rails you have a class Person and that class inherits from ActiveRecord::Base. Again, if your not that familiar with object-oriented terminology, inheritance just means that you are related and therefore have access to some of the same attributes and methods. By making the Person model a type of ActiveRecord it will have all kinds of methods already associated with it. Don't worry if this isn't totally clear yet, it will make more sense as soon as we start interacting with it. ActiveRecord makes a lot of assumptions now since we haven't explicitly said otherwise (e.g. that there is a table called people).
Installing A Database
Rails doesn't care too much what you use for a database server, but since we've gone this far away from Microsoft lets just go all the way to MySQL. I've been very impressed with the straight-forward simplicity of MySQL. No you cannot use C# in stored procedures, but I really don't want to anyway. First download the MySQL Windows Essentials - x86. Yes, it is only 16 megs. Can you see why I am fired up about this stuff?
Take all the default options
Uncheck the option to put a password on your MySQL server for now.
Press the execute button and now you have a full fledged SQL server running on your workstation!
Creating Our Development Database
We need to set up a database on our MySQL server (by convention called appname_development). We'll do this using the MySQL Command Line Utility that was installed on your start menu with the MySQL server and we will use the CREATE DATABASE databasename SQL command:- mysql> CREATE DATABASE rccjax_development;
- Query OK, 1 row affected (0.00 sec)
Quick review
So, quick review in case I've lost you: We set out to begin modeling our application. We identified the models that needed to be created and generated our application framework. We generated our first model for our application and just completed installing a database server with a database to house our data.
Setting Your Databse Options
Now, we will open up one of the files created by the application generator we ran earlier. The config\database.yml file tells Rails and ActiveRecord where to find the database depending on the mode that is initiated (development, test, and production). For right now, ignore all the commented lines (starting with the #) and look at the development configuration.
config\database.yml:
development:
adapter: mysql
database: rccjax_development
username: root
password:
host: localhost
Notice we are good to go without having to make any changes to our database configuration. This is where you could put in a password or change your adapter (if you relapsed and wanted to connect to MS SQL).
Setting Up Your Migration
So remember, we have our database but no table to house the data (attributes) associated with the Person objects. We need to create a table called people. Before you go start plugging in SQL code, lets have a look at another file that was created for you when you generated the Person model.
db\migrate\001_create_people.rb
- class CreatePeople <ActiveRecord::Migration
- def self.up
- create_table :people do |t|
- t.column :name, :string
- end
- end
- def self.down
- drop_table :people
- end
- end
This is especially cool. When I first learned Rails, I was creating tables on my own with MySQL tools. Now with "migrations" you can actually set up your whole database INDEPENDENT of which adapter you may be using. There is a lot more to migrations that we won't get into right now. For now, lets use this migration to create our table. Modify the file as follows:
db\migrate\001_create_people.rb
- class CreatePeople <ActiveRecord::Migration
- def self.up
- create_table :people do |t|
- t.column :first_name, :string
- t.column :last_name, :string
- t.column :email, :string
- t.column :home_phone, :string, :limit => 10
- t.column :business_phone, :string, :limit => 10
- t.column :mobile_phone, :string, :limit => 10
- t.column :street_address_1, :string
- t.column :street_address_2, :string
- t.column :city, :string
- t.column :state, :string
- t.column :zip, :string, :limit => 10
- t.column :sex, :string, :limit => 1
- t.column :created_on, :datetime
- t.column :updated_on, :datetime
- end
- end
- def self.down
- drop_table :people
- end
- end
Great! Notice, I have just defined the attributes associated with Person objects that I want stored in my database. Also, Rails will assume that I want to create a field named id to store the unique identifier of each object. The only thing left is to run the rake migrate command. We will be using rake to perform various tasks throughout application development in rails. In this case, it tells rake to migrate the current database to the most recent step stored in our migration folder -- version 1. Since we do not specify the environment, rake will assume development so it will migrate the rccjax_development database to version 1.
My Rails Projectsrccjax>rake migrate
(in C:/My Rails Projects/rccjax) == CreatePeople: migrating =========== -- create_table(:people) -> 0.0620s == CreatePeople: migrated (0.0620s) ===========
There you have it! You've just created your table without writing a line of SQL code. Notice also, if you changed your mind, you could run rake migrate VERSION=0 and it would drop the table.
Interacting With Your Model
So now ActiveRecord will be happy because the table exists and can be found because we've named it corresponding to the model name. The last thing I would like to do today is interact with our model a little bit. If you haven't learned any Ruby code yet, this is a great place to explore. We are going to enter interactive Ruby or the application console. To do this, you will enter the command ruby script/console in your application folder. This allows you to enter in Ruby code and see the results in real time. In this next snippet, I will create a new person and then save him to the database:
The prompt is >> and after each command, the results are displayed with a =>.
My Rails Projectsrccjax>ruby script/console
- Loading development environment.
- >> new_guy=Person.new
- => person :0x38508b0 @attributes={"created_on"=>nil, "city"=>nil, "zip"=>nil, "updated_on"=>nil, "street_address_1"=>nil, "street_address_2"=>nil, "business_phone"=>nil, "sex"=>nil, "home_phone"=>nil, "first_name"=>nil, "last_name"=>nil, "state"=>nil, "mobile_phone"=>nil, "email"=>nil}, @new_record=true>
Notice I entered in the Ruby code
new_guy=Person.new which created a new object, new_guy, that is an instance of the Person class. The result was displayed after the => and shows all of the attributes of the object.
- >> new_guy.first_name = 'Tom'
- => "Tom"
- >> new_guy.last_name = 'Rossi'
- => "Rossi"
- >> new_guy.save
- => true
Now I have assigned our
new_guy a first and last name and then saved him to the database.
- >> Person.count
- => 1
- >> tom = Person.find_by_first_name('tom')
- => Person:0x37df160 @attributes={"created_on"=>"2006-08-12 15:27:03", "city"=>nil, "zip"=>nil, "updated_on"=>"2006-08-12 15:27:03", "street_address_1"=>nil, "street_address_2"=>nil, "business_phone"=>nil, "id"=>"1", "sex"=>nil, "home_phon
- e"=>nil, "first_name"=>"Tom", "last_name"=>"Rossi", "state"=>nil, "mobile_phone"=>nil, "email"=>nil}>
- >> tom.last_name
- => "Rossi"
- >> tom.email = 'nospam@themolehill.com'
- => "nospam@themolehill.com"
- >> tom.save
- => true
First remember that our Person model had next to nothing defined other than specifying that it would inherit from ActiveRecord. ActiveRecord exposes all of the field names as attributes (.first_name, .last_name, etc.) of the object and also contains all of the methods I used in the previous code (.new, .find, .count). So notice, I was able to create a new object of class Person named new_guy and Rails knew all the attributes that could be defined. I set some values and then saved the new_guy to the database. When it was saved, it received the id of 1 and ActiveRecord went ahead and populated the created_on field for us. I then created a new object tom by calling a dynamic ActiveRecord method .find_by_fieldname. This went to the database found the record and than instantiated the new object tom. Both tom and new_guy point to the same object in the database. I was able to modify once again the attributes and then save back to the database. Cool stuff, huh?
Conclusion
Well, hopefully that is enough to get you started on your application modelling. In our next tutorial, we will complete the model and expand some of our interaction with the console. Send me your feedback! And please let me know if I said anything wrong or too confusing!
Give us a piece of your mind.
12 comments thus far - add yours