def acts_as_double_polymorphic_join options={}, &extension
collections, options = extract_double_collections(options)
options[:extend] = (if options[:extend]
Array(options[:extend]) + [extension]
else
extension
end) if extension
collection_option_keys = make_general_option_keys_specific!(options, collections)
join_name = self.name.tableize.to_sym
collections.each do |association_id, children|
parent_hash_key = (collections.keys - [association_id]).first
begin
parent_foreign_key = self.reflect_on_association(parent_hash_key._singularize).primary_key_name
rescue NoMethodError
raise PolymorphicError, "Couldn't find 'belongs_to' association for :#{parent_hash_key._singularize} in #{self.name}." unless parent_foreign_key
end
parents = collections[parent_hash_key]
conflicts = (children & parents)
parents.each do |plural_parent_name|
parent_class = plural_parent_name._as_class
singular_reverse_association_id = parent_hash_key._singularize
internal_options = {
:is_double => true,
:from => children,
:as => singular_reverse_association_id,
:through => join_name.to_sym,
:foreign_key => parent_foreign_key,
:foreign_type_key => parent_foreign_key.to_s.sub(/_id$/, '_type'),
:singular_reverse_association_id => singular_reverse_association_id,
:conflicts => conflicts
}
general_options = Hash[*options._select do |key, value|
collection_option_keys[association_id].include? key and !value.nil?
end.map do |key, value|
[key.to_s[association_id.to_s.length+1..-1].to_sym, value]
end._flatten_once]
general_options.each do |key, value|
if internal_options[key]
general_options[key] = Array(value) + Array(internal_options[key])
end
end
parent_class.send(:has_many_polymorphs, association_id, internal_options.merge(general_options))
if conflicts.include? plural_parent_name
(conflicts).each do |method_name|
unless parent_class.instance_methods.include?(method_name)
parent_class.send(:define_method, method_name) do
(self.send("#{singular_reverse_association_id}_#{method_name}") +
self.send("#{association_id._singularize}_#{method_name}")).freeze
end
end
end
unless parent_class.instance_methods.include?(join_name)
parent_class.send(:define_method, join_name) do
(self.send("#{join_name}_as_#{singular_reverse_association_id}") +
self.send("#{join_name}_as_#{association_id._singularize}")).freeze
end
end
else
unless parent_class.instance_methods.include?(join_name)
join_name_method = join_name.to_s.gsub('/', '_').to_sym
parent_class.send(:alias_method, join_name_method, "#{join_name_method}_as_#{singular_reverse_association_id}")
end
end
end
end
end