Elaina Polson

Musings of a Beginner Programmer

Bringing It All Together With ActiveRecord

Do you ever feel like you don’t know where you’re going but you’re in a huge hurry to get there? That’s how I felt my first week in New York, attempting to navigate the subway system…and now it’s how I feel most days at Flatiron, navigating my way through the various Learn labs.

I think most of us can relate to this hurried impatience. In a rush to get all of the tests to pass in each lab (and ultimately get those glowing green lights to show up), we sometimes forget to stop and ponder the purpose behind what we’re actually doing.

Take the playlister labs, for example. First we built a playlister application using simple domain modeling; then we abstracted away some of our code using our new object orientation skillset; and finally we refactored our code further, using class modules. For the love of Ada Lovelace, why does Flatiron keep making us build the same application in different ways?

When I saw the playlister application again in the Object Relational Mappers section in Learn this week, my first instinct was to throw my computer against the wall. That simple little playlister application had already given me enough grief during my first three weeks at Flatiron. But this week was different. This time, I had a new tool under my programming toolbelt: ActiveRecord. Thanks to ActiveRecord, I finally understand the purpose behind all of those tortuous playlister labs. In each new playlister lab, we used a new skill we learned to abstract away some of the exising code and make our application more functional. ActiveRecord was another step of abstraction that brought it all together.

So what’s so great about ActiveRecord? I’m glad you asked.

ActiveRecord is an Object Relational Mapping system used in Rails. Object Relational Mapping (or ORM) is a technique that connects the objects of an application to tables in a relational database management system. By using ActiveRecord’s ORM system, the properties and relationships of the objects in our applications can be easily stored and retrieved from a database. And here’s the kicker: We barely have to write any configuration code. Say goodbye to SQL statements and countless lines of repetitive database access code; ActiveRecord writes it for us!

Got the gist? Now, let’s break it down with an example. Imagine we are transported back in time, before ActiveRecord exists. Say we have a database filled with different songs. We want each of those songs to behave as an object. That means we need to define a class Song, and define various behaviors (methods) for our Song class so we can access and interact with the individual songs in our database as objects.

Our database will give us our data (our songs, in this case) in a nested array, where each row in the array is a different song.

Right now, it looks like this:

1
[[1, "Shake it Off", "Taylor Swift", "pop"]]

But we want each of our songs to be an object that looks like this:

1
[#<Song:0x007fadec898090 id: 1, title: "Shake it Off", artist: "Taylor Swift", genre: "pop">]

Without ActiveRecord, we would have to do some Object Relational Mapping on our own. We would need to write a method in our Song class that takes in a row, and turns that row into a song object. That method might look a little something like this:

1
2
3
4
5
6
7
8
  def self.new_from_db(row)
    self.new.tap { |s|
      s.id = row[0]
      s.title = row[1]
      s.artist = row[2]
      s.genre = row[3]
    }
  end

And then if we wanted to find our song in a database by it’s title, we’d have to write a method like this:

1
2
3
4
5
6
7
8
9
  def self.find_by_title(title)
    sql = <<-SQL
      SELECT * FROM songs WHERE title = ?
    SQL

    DB[:conn].execute(sql, title).map do |row|
      self.new_from_db(row)
    end.first
  end

And what if we wanted to find a song by its artist, or by its genre, or its id number? More methods. And then what if we wanted to insert a new song from a given set of attributes and save it to our database? More methods. And THEN what if had an artists database and wanted to create an Artist class that behaves similarly to our Song class? This is starting to feel really repetitive. There must be an easier way to do this.

Enter, ActiveRecord. ActiveRecord is smart. It knows that our rows are objects. It maps one row in our database to one object in Ruby. And it assumes certain behaviors for those data objects – which saves us from writing the same lines of code over and over again.

Still not convinced ActiveRecord is amazing? Let’s look at some of the work ActiveRecord saves us from doing.

First, we need to set up ActiveRecord. The first step is to connect to our database:

1
2
3
4
ActiveRecord::Base.establish_connection(
  :adapter => "sqlite3",
  :database => "db/songs.sqlite"
)

And then, we create our songs table using ActiveRecords migrations (which I won’t get into now, but is another amazing feature of ActiveRecord):

1
2
3
4
5
6
7
8
9
class CreateStudents < ActiveRecord::Migration
  def change
    create_table :songs do |t|
      t.string :title
      t.string :artist
      t.string :genre
    end
  end
end

And finally, we want to extend our Song class with ActiveRecord’s model class.

1
2
class Song < ActiveRecord::Base
end

And now that our setup is finished, we can use all of ActiveRecord’s amazing, built-in methods!

So, if we wanted to insert a new song to our database, instead of writing our own insert method using SQL in Ruby, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  def insert
    sql = <<-SQL
      INSERT INTO songs (title, artist, genre) VALUES (?, ?, ?)
    SQL

    DB[:conn].execute(sql, title, artist, genre)
    @id = DB[:conn].execute("SELECT last_insert_rowid() FROM students")[0][0]
  end

  shake_it_off = Song.new
  shake_it_off.title = "Shake it Off"
  shake_it_off.artist = "Taylor Swift"
  shake_it_off.genre = "pop"

  shake_it_off.insert

We can just write:

1
  shake_it_off = Song.create(title: Shake it off, artist: Taylor Swift, genre: pop)

ActiveRecord gives us the create method, which initializes a new instance of our class, assigns it the attributes we give it, and saves it to our database, all in one line!

And our Song class still looks like this:

1
2
class Song < ActiveRecord::Base
end

What gives? Where are our methods? That’s the beauty of ActiveRecord.

Without ActiveRecord, you’re required to write A LOT of configuration code every time you want to treat your data as objects in an application. But ActiveRecord makes assumptions about our data, and gives us almost all of that configuration for free. A quote from the Rails guide sums it up nicely:

“The idea is that if you configure your applications in the very same way most of the time then this should be the default way. Thus, explicit configuration would be needed only in those cases where you can't follow the standard convention.”

Basically, ActiveRecord sees our Song class, and assumes it must map to a database table called songs. Then it looks in the songs table and realizes each column in that table is an attribute so it adds methods for both getting and setting that attribute. There’s no such thing as a free lunch. But free methods? ActiveRecord has got you covered. As long as you set up your models and tables correctly, ActiveRecord does the rest.

 

When we learned ActiveRecord this week, my first reaction was to wonder why on earth Flatiron made us map our database rows to objects ourselves and then make us write out all those annoying getting and setting and finding methods by hand using SQL statements. If they had just taught us ActiveRecord first, that would’ve made our lives WAY easier. But now I realize that if we hadn’t done it the hard way in the beginning, I wouldn’t appreciate or understand the amazingness of ActiveRecord. Everything we’ve done in each playlister lab is still there in the final product - SQL, object orientation, ORM, etc. We’re still using these things, but at a higher level. It may not seem like it on the surface, but they’re there. ActiveRecord has just abstracted them away.

ActiveRecord has made a lot of what we’ve been doing at Flatiron for the last three weeks make so much more sense. While I’m still not entirely sure where I’m going all the time, I feel like I’ve been given a map - sure, maybe it’s a faded, half-finished map, without an end-point in sight, but a map nonetheless. And I can’t wait for more of it to come together.

PSST, if you want to learn more about ActiveRecord, read this guide!