Here attached is the diff that patches the cached_model to cache correctly descendants in single inheritance models.
For example: We have some contacts that might be on might not be a users of our service. We want to represent them as
the following class hierarchy.
class Contact < ActiveRecord:Base
end
class AddressBookEntry < Contact
end
class User < Contact
end
So we have the migration:
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
# common attributes
t.column :name, :string, :null => false
t.column :insertions, :string
t.column :surname, :string, :null => false
t.column :company, :string
t.column :num_internal, :string
t.column :num_other, :text
t.column :address, :string
t.column :postal, :string
t.column :city, :string
t.column :email, :string
t.column :notes, :text
t.column :type, :string
t.column :created_at, :timestamp
t.column :updated_at, :timestamp
# attributes for type=User
t.column :login, :string
t.column :passwd, :string
t.column :salt, :string
end
execute <<-ALTER
ALTER TABLE contacts ALTER COLUMN created_at SET DEFAULT now();
ALTER TABLE contacts ALTER COLUMN updated_at SET DEFAULT now();
ALTER
end
def self.down
drop_table :contacts
end
end
This stores all those records in one table for all class objects of given hierarchy. The difference on SQL level between
these objects is the value of 'type' column, but id is unique among all of these stored objects.
So idea is brain-dead simple: we cache these objects tagged with their base class name (Contact in our case) and object's
id which is unique in hierarchy.
Ruby Object.base_class always returns the topmost class in the inheritance ierarchy, so we put it in tag generation
and change the regular expression a little bit in find_by_sql to understand Rail's way of fetching such objects.
In our case Rails will produce SQLs like:
SELECT * FROM contacts WHERE (contacts.id = 1) AND ( (contacts."type" = 'Contact' OR contacts."type"
= 'AddressBookEntry' OR contacts."type" = 'User' ) ) LIMIT 1
Patched cached_model will store this object in cache with tag active_record:Contact:1.
Cheers. |