Skip to content

Instantly share code, notes, and snippets.

@troyk
Created March 9, 2012 10:51
Show Gist options
  • Select an option

  • Save troyk/2006057 to your computer and use it in GitHub Desktop.

Select an option

Save troyk/2006057 to your computer and use it in GitHub Desktop.
Neat little STI association trick, works with to_json but finder include needs some love
# Objective: An association using STI should only query the db once for the base class
class Contact < ActiveRecord::Base
has_many :info, :class_name=>'::Contact::ContactInfo'
has_many :phones, :class_name=>'::Contact::Phone'
has_many :emails, :class_name=>'::Contact::Email'
has_many :addresses, :class_name=>'::Contact::Address'
# load all info's thorugh info
# this is possible due to how associations are mixed into the class via a module
def info
unless info_assoc = @association_cache[:info]
info_assoc = self.association(:info)
a = {:phones => [], :emails => [], :addresses => []}
info_assoc.load_target.each do |info|
a[:phones].push(info) and next if info.is_a?(::Contact::Phone)
a[:emails].push(info) and next if info.is_a?(::Contact::Email)
a[:addresses].push(info) and next if info.is_a?(::Contact::Address)
end
a.each { |assoc_name, records| self.association(assoc_name).target = records }
end
info_assoc
end
def phones; self.info; super; end
def emails; self.info; super; end
def addresses; self.info; super; end
class ContactInfo < ActiveRecord::Base
set_table_name "contacts_info"
end
class Email < ContactInfo
end
class Phone < ContactInfo
end
class Address < ContactInfo
end
end
# to_json works like a charm
>> Contact.first.to_json(:include=>[:phones,:emails,:addresses])
D, [2012-03-09T02:50:21.378127 #47368] DEBUG -- : Contact Load (0.6ms) SELECT "contacts".* FROM "contacts" LIMIT 1
D, [2012-03-09T02:50:21.380086 #47368] DEBUG -- : Contact::ContactInfo Load (0.5ms) SELECT "contacts_info".* FROM "contacts_info" WHERE "contacts_info"."contact_id" = 1
# finder includes, meh...
>> Contact.first(:include=>[:phones,:emails,:addresses]).to_json(:include=>[:phones,:emails,:addresses])
D, [2012-03-09T02:46:09.721232 #47368] DEBUG -- : Contact Load (0.7ms) SELECT "contacts".* FROM "contacts" LIMIT 1
D, [2012-03-09T02:46:09.722783 #47368] DEBUG -- : Contact::Phone Load (0.6ms) SELECT "contacts_info".* FROM "contacts_info" WHERE "contacts_info"."type" IN ('Contact::Phone') AND "contacts_info"."contact_id" IN (1)
D, [2012-03-09T02:46:09.730487 #47368] DEBUG -- : Contact::Email Load (0.4ms) SELECT "contacts_info".* FROM "contacts_info" WHERE "contacts_info"."type" IN ('Contact::Email') AND "contacts_info"."contact_id" IN (1)
D, [2012-03-09T02:46:09.731696 #47368] DEBUG -- : Contact::Address Load (0.4ms) SELECT "contacts_info".* FROM "contacts_info" WHERE "contacts_info"."type" IN ('Contact::Address') AND "contacts_info"."contact_id" IN (1)
D, [2012-03-09T02:46:09.732826 #47368] DEBUG -- : Contact::ContactInfo Load (0.3ms) SELECT "contacts_info".* FROM "contacts_info" WHERE "contacts_info"."contact_id" = 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment