Skip to content

Instantly share code, notes, and snippets.

@diebels727
Created March 18, 2011 00:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save diebels727/875399 to your computer and use it in GitHub Desktop.
Save diebels727/875399 to your computer and use it in GitHub Desktop.
Super-Meta-Polymorphic
#Where the associations table has sourcable_id,sourcable_type,targetable_id,targetable_type
class Association < ActiveRecord::Base
include Relatable
belongs_to_association :sourcable => :sourcable, :targetable => :targetable
end
#OR _any_ table that we want to be an association table can become one (if the source and target id and type columns do not exist, then the mixin creates them)
class AssociationTables < ActiveRecord::Base
include Relatable
belongs_to_association :sourcable => :left_side, :targetable => :right_side
end
#Old stuff below....
#Where the association looks like:
# sourcable_id: <email_id>, sourcable_type: Email, targetable_id: <phile_id>, targetable_type: Phile
#
#
#What I think may be an easy solution is to write a dynamic extension to implement sourcable or targetable on a per-instance basis:
#
#For example:
# e = Email.new
# e.targetable
# e.associations << a
#
# Which enables this instance of Email to be an association target; which would allow us to do something like this:
#
# e = Email.new
# e.targetable
# e.associations << a
# e = Email.new
# e.sourcable
# e.associations << a
#
# Still doesn't enable e.sources or e.targets (or perhaps e.linked_to?)
#
# To accomplish this, I was looking in to using the dynamic finders -- So, Association.where(:sourcable_type => Email). This does return all of the
# email associations that are sources.
#Which allows email.associations << a
class Email < ActiveRecord::Base
include Relatable
acts_as_association :associations, :as => :sourcable
end
#OR
class Email < ActiveRecord::Base
include Relatable
acts_as_association :association_tables, :as => :left_side
end
#So long as you have build the tables model w/ belongs_to_association :sourcable => :left_side, :targetable => :right_side
#Which allows phile.associations << a
class Phile < ActiveRecord::Base
include Relatable
acts_as_association :associations, :as => :targetable
end
#OR
class Phile < ActiveRecord::Base
include Relatable
acts_as_association :association_tables, :as => :right_side
end
#And now that we're super-polymorphic we can even state:
class Phile < ActiveRecord::Base
include Relatabe
acts_as_association :associations, :as => :targetable
acts_as_association :association_tables, :as => right_side
end
Phile
-----
|id|
| 1|
Associations
------------
|id|sourcable_id|sourcable_type|targetable_id|targetable_type|
|10| | | 1| Phile|
AssociationTables
-----------------
|id|left_id|left_type|left_id|left_type|
|10| | | 1| Phile|
p.associations => all associations for this instance of Phile
r = Association.where(:targetable_type => 'Phile') => all associations of type Phile
l = Association.where(:sourcable_type => 'Phile') => all associations of type Phile
r + l => union (e.g. ALL associations of type Phile)
rt = AssociationTables.where(:targetable_type => 'Phile')
lt = AssociationTables.where(:sourcable_type => 'Phile)
rt + lt + r + l => All associations of type Phile across both tables
module Relatable
module ClassMethods
#acts_as_association <whatever I belong to>, :as => <key for left or right side>
def acts_as_association(associations,relationship)
Rails.logger.debug("DEBUG: #{self}")
self.class_eval( "has_many \"#{associations.to_sym}\", :as => \"#{(relationship[:as].to_sym)}\"" )
end
#belongs_to_association :sourcable => <key for left side>,:targetable => <key for right side>
def belongs_to_association(relationships)
(sourcable,targetable) = relationships[:sourcable],relationships[:targetable]
#Better way to handle this is to not generate any exceptions
begin
#Keys are generated dynamically
add_association_columns( (sourcable.to_s+"_id").to_sym => :integer , (sourcable.to_s+"_type").to_sym => :string,
(targetable.to_s+"_id").to_sym => :integer, (targetable.to_s+"_type").to_sym => :string )
rescue Exception => e
Rails.logger.debug( "Columns already exist for #{sourcable} and #{targetable}" )
end
self.class_eval( "belongs_to \"#{sourcable}\", :polymorphic => true\n
belongs_to \"#{targetable}\", :polymorphic => true" )
end
#Columns are generated via dynamic migration; so now our 'association' truly is polymorphic
def add_association_columns(association_columns)
association_columns.each { |k,v| ActiveRecord::Migration::add_column self.to_s.tableize.to_sym, k, v }
end
end
def instance_acts_as_association(associations,relationship)
Rails.logger.debug("DEBUG: #{self}")
end
def self.included(base)
base.extend(ClassMethods)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment