Consider the following example code:
def Product < ActiveRecord::Base
end
def Book < Product
end
(I gave up finding a name for this kind of relationship. I thought Book is a “child model” and Product is the “parent,” but that is incorrect. For example, a Comment model object linked to another Comment model object is what would be a “child-parent” relationship. If you have a better way to describe the relationship of the models in my code above, you’re welcome to write it down here. Either way, this is not really why I’m here.)
Of course, with the code above, the Book model will share the same database table than Product, “products.” The model type will be saved as a string in the table’s “type” column. So, calling Product.create will insert a row in the table with the type value set to “Product” and using with Book.create will do the same but with the value of “Book.”
What puzzles me, however, is calling Book.last will return the last row with the type “Book,” as I expect it, but Product.last will return the last row no matter what type, including “Product” and “Book,” even though I wish to only get the last “Product.”
I tried defined a default_scope in Product which I override in my Book, but that causes more problems than it solves, and messed up my named scopes in Product which are inherited by Book.
Is there a way to make Product.last return the last object of type “Product” and avoid any objects of type “Book”?
Thanks in advance for your answers.
The basic misunderstanding here seems to be between the concept of “relationships” or “associations” (such as “has_one”, “belongs_to”, etc.), and the object oriented concept of inheritance.
Read up on this: http://rubylearning.com/satishtalim/ruby_inheritance.html
Based on your example, I think you’ve got the concept of associations figured out, but you’re confusing it with inheritance, which isn’t the same, and you’re not quite understanding here.
When a class inherits from another class (in your example, Book inherits from Product), the “child” class gets all the functionality of the “parent” class, plus any new functionality that it adds on top of that.
Because of that, all Books are Products, but not all Products are Books.
The reason Product.last returns the last row in the products table regardless of type, is because all Products (including Books) are products. So, a Book IS a product, therefore if the last Product is a Book, that will be returned.
Ok, so the easiest way to accomplish what you’re trying to do here is to define all types of Products as sub-types of Product, and never use Product.last.
Let’s say you’re keeping track of Books, CDs, and Cars
class Book < Product
class CD < Product
class Car < Product
This way, when you need to get the newest Book, CD, or Car added to the database, you do Book.last, CD.last, or Car.last. If you just need to know the newest Product of any type, you do Product.last.