We all know that Ruby objects are actually alive (or at least Rubyists tend to treat our objects as if they were). At certain points in our object's life cycle, accordingly, we may want to automatically trigger certain actions. This is where the callback feature of Active Record kicks in.
source: www.dhgate.com
Let's look at the example of the Sinatra Student Scraper project we've been working on at Flatiron this week. Briefly, the aim of this lab is to scrape our Ruby 007 class site and recreate it using that info, an ActiveRecord ORM and Sinatra.
So, we have a students table in our databse containing columns for a student's name, bio, education and other attributes. Through Active Record, these columns become methods on the Song model class. However, in order for our Sinatra app to have some pretty, conventional URLs (for example, if I want to visit my personal page on our class site, I should be able to go to "http://www.example.com/students/sophie-debenedetto"), we need to create a slug for each individual student.
Enter the "slugify" method. This method of the Song class will take a student's anme and turn it into a URL slug.
def slug
self.name.downcase.gsub(' ','-') if
self.name != nil
end
Great, now we have a method we can call on any song ojbect to get it's slug. But...we have no way to persist this information into our database. This means I can't save a song's slug for future use--everytime I want the slug of a particular song, I'll have to call this method. As programmers, we're lazy, and we want to enable Ruby to be lazy too. By Active Record callbacks, Ruby only has to create a slug for a song once.
At what point in time might we want this occur? Right after each student is instantiated and saved into the students table in our database, we want a slug to be made for that student and we want to save that slug into our database. Here's how we can do it:
First, make sure your students table has a 'slug' column. Then...
class Student < ActiveRecord::Base
after_create :slugify!
def slugify!
self.slug = self.name.downcase.gsub(' ','-')
if self.name != nil
self.save
end
Let's talk about what just happened. The after_create
macro, offered by Active Record, tells our slugify!
method to fire automatically right after each new student is created.
Our slugify!
method:
- Creates a slug using the code we previously developed for our earlier (and now replaced)
slug
method, - Sets the
slug=
method (which we have because we added a slug column to our students table) equal to the slugified student's name, - Persists that student's slug into the database with
self.save
.
And we're done! Each student has a slug attribute that persists in our database and we hardly had to lift a finger.