Database Legos

This past week at Flatiron has introduced us to ORMs--databases wrapped in Ruby--and to Active Record (just a bit though!).

One source of confusion among me and my classmates has been the basic relationship between the database and the actual objects created by the Ruby program. In order to help clarify this relationship, I thought we could play with Legos.

img
source: lego.com

(metaphorically though. I can't let you play with that--it's only for ages 9+).

Instantiating an object

So, pretend you're 9 years old and you just recieved this awesome Lego Star Wars ship-thing (sorry, I've never really watched Star Wars) as a present. You open up the box, read the directions and assemble your space ship(?).

This is the same thing that happens when we instantiate a new object of a Ruby class:

def SpaceShip
	attr_accessor :name, :size, :color :other_spaceshipstuff
	def initialize(name)
		@name = name
	end
end

#instantiate a new Spaceship:
the_battlestar_galactica = Spaceship.new("Galactica")

Storing your object in the database

Then, all of a sudden, its bed time! Your parents tell you to put away your toys. Your battlestar galactica won't fit inside your toy box (sorry I'm mixing my metaphors here, but Battlestar Galactica is way better than Star Wars). So, you disassemble your toy and put all the legos back into the box.

This is what occurs when you 'save' an object in your database.

First, let's create our database connection and our spaceships table:


DB = {:conn => SQLite3::Database.new("db/spaceships.db")}

def self.create_table 
    sql = "CREATE TABLE IF NOT EXISTS spaceships (name, color, other_spaceship_stuff)"
    DB[:conn].execute(sql)
  end
end

Now, we're reading to implement our 'save' or 'insert' method. This will store our spaceship in the spaceships table in the spaceships database.

def insert
    sql = "INSERT INTO spaceships (name, color, other_spaceship_stuff) VALUES (?, ?, ?)
    DB[:conn].execute(sql, [self.name, self.color, self.other_spaceship_stuff])

self.id = DB[:conn].execute("SELECT last_insert_rowid() FROM students")[0][0]
end

Effectively, we've just taken apart our battslestar (object) and stored it as individual legos (raw data) in our toy box (database). What is inserted into the database isn't the spaceship object itself, but rather the raw data that make up the attributes of that object.

Reconstituting the spaceship, or, fetching the object from the database

Okay, its morning and you're reading to play Battlestar Galactica again (because your parents let you watch age inappropriate TV? I don't know.)

You go to your toy box and take our...individual legos! You need to reassemble them into a spaceship in order to play your game. This is akin to the function of find_by_name and new_from_db functions in your SpaceShip class. When you enter your database to find an object you store, you don't leave that database with an object--you leave the the raw data you stored the object as and you need to reconstitute it into (the same!) object.


def new_from_database(row)
    self.new.tap do |spaceship|
         spaceship.name = row[0]
         spaceship.color = row[1]
         spaceship.other_spaceship_stuff = row[2]
    end
  end
  
def find_by_name(name)
	sql = "SELECT * FROM spaceships WHERE name = ?" 	spaceship_raw_data = DB[:conn].execute(sql, [self.name])
    self.new_from_database(spaceship_raw_data)
  end

With the find_by_name method, you went into your toy box (database) and got your giant pile of legos (raw data). Remember, the "SELECT FROM table" SQL query will return an array of raw data.

Then, your new_from_db method is called to take that row and reconstitute the object with that data.

Just one more thing before you go forth and build awesome ORMs: Battlestar Galactica > Star Wars.
img
source: wired.com

subscribe and never miss a post!

Blog Logo

Sophie DeBenedetto

comments powered by Disqus
comments powered by Disqus