Add the has_many_polymorphs plugin
[cs356-p2-videostore.git] / vendor / plugins / has_many_polymorphs / lib / has_many_polymorphs / base.rb
1
2 module ActiveRecord
3   class Base
4     
5     class << self
6     
7       # Interprets a polymorphic row from a unified SELECT, returning the appropriate ActiveRecord instance. Overrides ActiveRecord::Base.instantiate_without_callbacks.
8       def instantiate_with_polymorphic_checks(record)
9         if record['polymorphic_parent_class']
10           reflection = record['polymorphic_parent_class'].constantize.reflect_on_association(record['polymorphic_association_id'].to_sym)
11 #          _logger_debug "Instantiating a polymorphic row for #{record['polymorphic_parent_class']}.reflect_on_association(:#{record['polymorphic_association_id']})"
12
13           # rewrite the record with the right column names
14           table_aliases = reflection.options[:table_aliases].dup
15           record = Hash[*table_aliases.keys.map {|key| [key, record[table_aliases[key]]] }.flatten]          
16           
17           # find the real child class
18           klass = record["#{self.table_name}.#{reflection.options[:polymorphic_type_key]}"].constantize
19           if sti_klass = record["#{klass.table_name}.#{klass.inheritance_column}"]
20             klass = klass.class_eval do compute_type(sti_klass) end # in case of namespaced STI models
21           end
22           
23           # check that the join actually joined to something
24           unless (child_id = record["#{self.table_name}.#{reflection.options[:polymorphic_key]}"]) == record["#{klass.table_name}.#{klass.primary_key}"]
25             raise ActiveRecord::Associations::PolymorphicError, 
26               "Referential integrity violation; child <#{klass.name}:#{child_id}> was not found for #{reflection.name.inspect}" 
27           end
28           
29           # eject the join keys
30           # XXX not very readable
31           record = Hash[*record._select do |column, value| 
32             column[/^#{klass.table_name}/]
33           end.map do |column, value|
34             [column[/\.(.*)/, 1], value]
35           end.flatten]
36                     
37           # allocate and assign values
38           returning(klass.allocate) do |obj|
39             obj.instance_variable_set("@attributes", record)
40             obj.instance_variable_set("@attributes_cache", Hash.new)
41             
42             if obj.respond_to_without_attributes?(:after_find)
43               obj.send(:callback, :after_find)
44             end
45             
46             if obj.respond_to_without_attributes?(:after_initialize)
47               obj.send(:callback, :after_initialize)
48             end
49             
50           end
51         else                       
52           instantiate_without_polymorphic_checks(record)
53         end
54       end
55       
56       alias_method_chain :instantiate, :polymorphic_checks 
57     end
58     
59   end
60 end