I’ve inherited an Entity-Attribute-Value (EAV) database setup at work. I’ve never really seen this used at the scale that it was used. EAV’s are great for rapidly changing database fields, until now I’ve seen them mostly for select box’s and configurations.
In my instance, I have a main table for items and the rest of the attributes can be looked up. EAV’s in Rails actually is easier than it was implemented in PHP. However, the ever changing attributes would be better setup using meta-programing.
In my model, I define an attributes method, like so:
def attributes
@attribute ||= {}
end
This makes an attribute instance available for my method_missing call. In particular, I’ll need to make a call to the database, so this caches the result for me.
Now for the real magic. Typically, the item record has an id, itemcode, product_type, and title. So I can call “item.title” and get the item’s title. Other attributes like the “subtitle”, “price”, and “image” are not. Using method_missing I can get at them as if they were part of the item model.
def method_missing(method)
begin
super
rescue
return attributes[method.to_sym] if attributes[method.to_sym]
attributes[method.to_sym] = Attribute::get(itemcode, method.to_s) unless method.nil? || method.blank?
end
end
The begin… rescue blocks test method missing and rescue block is the code needed access the attributes. Calling super, keeps method_missing functionality in place. If that fails, it checks the attributes hash, then calls the Attribute::get method.
With over 330 possible attributes (and counting), I’ll be able to access them all like they are part of the item!