Peel - Day 2 - Could it be This Easy?
It seems silly that it has taken me so long to realize that the goal isn’t to create an Active Record object, it’s to create an interface for dynamically adding Active Record behavior to a class.
I’m not sure I worded that well, so let me try to break it down, for my own sake.
In our class,
Book, we shouldn’t define a class-level method called
.find(). Instead, this should be dynamically added to the ancestry chain, so that when we call
Book.find(), and it doesn’t exist inside
Book, Ruby knows to look up the hierarchy to find where that method is defined.
Likewise for the instance methods, like
#update(). Instead of “hardcoding” that method inside of the
Book class, we’ll want to establish an interface that will allow Ruby to delegate to where that method is defined.
With that said, the challenge of defining these methods, (
#update(), etc.) continues. How do we define them in an abstract way so that the their behavior is adjusted during runtime? What interface do we make available to classes who wish to add this behavior?
Construct an instance of the Active Record from an SQL result set row.
We want to define a class…
class Book end
Where we can call a method like
Which will in turn make a call to
SQLite3 and execute a
SQLite3::Database.new("books_app") .execute("SELECT * FROM books WHERE id = 1;")
And return to us a
Book instance that contains the data from the result set row, as attributes on the object.
# => #<Book:0x007fa903965e98 @author="Metz, Sandi", @id=1, @isbn="9780321721334", @title="Practical Object Oriented Design in Ruby">
The bulk of the work in this flow lies in the
SQLite3 execute method. This method has a lot of knowledge:
SQLite3::Database.new()means it depends on the
SQLite3library and knows how to get a new instance of a database object.
"books_app"is the name of the database.
execute()is the name of the method on the SQLite database instance that executes an SQL query.
"SELECT * FROM ... WHERE ..."is the SQL query string to be run.
booksis the name of the database table.
idis that name of the column.
1is the id we’re querying for.
Managing how all of that knowledge gets to our persistence layer is a vital part of this problem.
Another piece of the problem is how
Book ends up with a
.find() class method and how our persistence layer knows how to construct a new
Book instance, once it’s retrieved that data from the database.