ActiveRecord is sexy
It’s time to meet ActiveRecord, the heart of Rails in my opinion. ActiveRecord handles all interactions with your data and effectively turns your database results into workable objects for your code. This is called Object Relational Mapping and it’s very useful. How it works is ActiveRecord takes a look at your database and if certain conventions are met (or you give it enough of a nudge) it can interpret table names, columns and column values as an object for you to manipulate. Say we have a table called shows
that contains tv show information and it looks like this:
id | name | description | day | rating_id | genre_id |
1 | Veronica Mars | kick-ass, snarky sleuth | 2 | 5 | 2 |
2 | My Name is Earl | karma hurts | 4 | 4 | 1 |
It’s important to have an id column as the primary key (with auto increment) for every table that represents and object in your code
We can clue ActiveRecord in about shows
with the following:
class Show < ActiveRecord::Base
end
Yeah it’s empty, for the moment, but even with just this Active Record can deduce that there is a table called shows
and it should map the rows it grabs from it to use an object called Show
. These object inherit from ActiveRecord helpful methods that will let us play with these rows to our hearts content. Here’s a taste:
#############################################################
### You *only* need the following for standalone ruby ###
### Not within rails itself; just outside ###
require 'rubygems'
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:database => 'db/your_database_here.db' )
### okay, back to your regularly scheduled program ###
#############################################################
@shows = Show.find(:all) # => array of Show objects
@shows.size # => 2
@shows.first.name # => "Veronica Mars"
Show.create :name => 'New Show', :description => 'It will be great' # => new Show object
@shows = Show.find(:all) # => array of Show objects
@shows.size # => 3
@shows.last.name # => "New Show"
@earl = Show.find_by_name "My Name is Earl" # => Show object for My Name is Earl
@earl.name # => "My Name is Earl"
@earl.name = "My Name Is Earl" # => "My Name Is Earl"
@earl.save # saves to database with modification
Validate this!
That’s fun, but there’s more. If we need to ensure that some fields are always present, or maybe that they’re a certain size or any other checks how would we do that? Heading back to our Show
object, we can add a number of validates_*
options like so:
class Show < ActiveRecord::Base
validates_presence_of :name # if no name is specified than fail
validates_length_of :name, :maximum => 50 # can't be greater than 50
validates_numericality_of :day # must be a number
If we try to test those boundaries…
show = Show.new :description => 'No Name', :day => 'Monday'
show.save # => false (won't save it)
show.errors.empty? # => false
show.errors.count # => 2
show.each_full { |msg| puts msg }
# => "Name can't be blank" +
"Day is not a number"
show.attributes = { 'name' = 'The Amazing Race', 'day' = 3 }
show.save # => true
That deserves a Montgomery Burns “eggscelllent” dance.
Associations & You
You might be wondering when I was going to mention rating_id
and genre_id
. What’s that all about? Just setting the stage for associations. There’s more to TV shows than name and description and the same is true for most things you’d store in a database. Otherwise it would be simpler to stick with a text file like a CSV or a spreadsheet. Here’s a wider look at the database, including two other tables ratings
and genres
:
id | name | description | day | rating_id | genre_id |
1 | Veronica Mars | kick-ass, snarky sleuth | 2 | 5 | 2 |
2 | My Name Is Earl | karma hurts | 4 | 4 | 1 |
3 | The Amazing Race | No Name | 3 | null | null |
id | name |
1 | Comedy |
2 | Drama |
3 | Science Fiction/Fantasy |
4 | Children’s |
5 | Sports |
6 | News/Entertainment |
7 | Reality |
id | audience |
1 | Y |
2 | Y7 |
3 | G |
4 | PG |
5 | TV14 |
6 | TVMA |
Notice that in the original shows
table the column names were the singular form of the association followed by id (eg: rating_id
). This convention signals the foreign key relationship; it can be specifically set with the :foreign_key
option
To use these in our application, we need to add some code to our Show
object and make Rating
and Genre
objects.
class Show < ActiveRecord::Base
belongs_to :rating
belongs_to :genre
end
class Rating < ActiveRecord::Base
has_many :shows
end
class Genre < ActiveRecord::Base
has_many :shows
end
Use belongs_to
for the table that contains the foriegn key (eg. ratings_id
)
This setups up a 1-to-many relationship. A show has a rating and ratings hold many shows. There’s a lot to associations, but for now let’s look at this simple has_many
relationship.
@earl = Show.find_by_name "My Name Is Earl"
@earl.rating.audience # => "PG"
@earl.rating.genre # => "Comedy"
With the relationships setup with has_many
, ActiveRecord connected the dots from Earl’s rating_id
of 4
to the rating PG
whose id
is 4
. Let’s move on to make associations by adding a rating and genre to “The Amazing Race.”
@tar = Show.find 3 # look up by id
@tar.rating = Rating.find_by_audience("PG")
@tar.genre = Genre.find_by_name("Reality")
@tar.description = "race around the world"
@tar.save
shows:
id | name | description | day | rating_id | genre_id |
1 | Veronica Mars | kick-ass, snarky sleuth | 2 | 5 | 2 |
2 | My Name Is Earl | karma hurts | 4 | 4 | 1 |
3 | The Amazing Race | No Name | 3 | 4 | 7 |
Simple enough eh? We’ll be going over other types of associations in class and later on in the course.