Class: ActiveRecord::Base

Inherits:
Object show all
Extended by:
Associations::PolymorphicClassMethods
Defined in:
lib/has_many_polymorphs/base.rb,
lib/has_many_polymorphs/support_methods.rb,
lib/has_many_polymorphs.rb

Constant Summary collapse

COLLECTION_METHODS =
[:belongs_to, :has_many, :has_and_belongs_to_many, :has_one, 
    :has_many_polymorphs, :acts_as_double_polymorphic_join].each do |method_name|
  alias_method "original_#{method_name}".to_sym, method_name
  undef_method method_name
end
GENERATED_CODE_DIR =
"#{RAILS_ROOT}/generated_models"

Constants included from Associations::PolymorphicClassMethods

Associations::PolymorphicClassMethods::RESERVED_DOUBLES_KEYS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Associations::PolymorphicClassMethods

acts_as_double_polymorphic_join, create_has_many_polymorphs_reflection, has_many_polymorphs

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/has_many_polymorphs/debugging_tools.rb', line 55

def method_missing(method_name, *args, &block)
  if COLLECTION_METHODS.include? method_name.to_sym
    Dir.chdir GENERATED_CODE_DIR do
      filename = "#{demodulate(self.name.underscore)}.rb"
      contents = File.open(filename).read rescue "\nclass #{self.name}\n\nend\n"
      line = caller[1][/\:(\d+)\:/, 1]
      contents[-5..-5] = "\n  #{method_name} #{args[0..-2].inspect[1..-2]},\n     #{args[-1].inspect[1..-2].gsub(" :", "\n     :").gsub("=>", " => ")}\n#{ block ? "     #{block.inspect.sub(/\@.*\//, '@')}\n" : ""}     # called from line #{line}\n\n"
      File.open(filename, "w") do |file| 
        file.puts contents             
      end
    end
    # doesn't actually display block contents
    self.send("original_#{method_name}", *args, &block)
  else
    self.send(:original_method_missing, method_name, *args, &block)
  end
end

Class Method Details

.instantiate_with_polymorphic_checks(record) ⇒ Object

Interprets a polymorphic row from a unified SELECT, returning the appropriate ActiveRecord instance. Overrides ActiveRecord::Base.instantiate_without_callbacks.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/has_many_polymorphs/base.rb', line 8

def instantiate_with_polymorphic_checks(record)
  if record['polymorphic_parent_class']
    reflection = record['polymorphic_parent_class'].constantize.reflect_on_association(record['polymorphic_association_id'].to_sym)
#          _logger_debug "Instantiating a polymorphic row for #{record['polymorphic_parent_class']}.reflect_on_association(:#{record['polymorphic_association_id']})"

    # rewrite the record with the right column names
    table_aliases = reflection.options[:table_aliases].dup
    record = Hash[*table_aliases.keys.map {|key| [key, record[table_aliases[key]]] }.flatten]          
    
    # find the real child class
    klass = record["#{self.table_name}.#{reflection.options[:polymorphic_type_key]}"].constantize
    if sti_klass = record["#{klass.table_name}.#{klass.inheritance_column}"]
      klass = klass.class_eval do compute_type(sti_klass) end # in case of namespaced STI models
    end
    
    # check that the join actually joined to something
    unless (child_id = record["#{self.table_name}.#{reflection.options[:polymorphic_key]}"]) == record["#{klass.table_name}.#{klass.primary_key}"]
      raise ActiveRecord::Associations::PolymorphicError, 
        "Referential integrity violation; child <#{klass.name}:#{child_id}> was not found for #{reflection.name.inspect}" 
    end
    
    # eject the join keys
    # XXX not very readable
    record = Hash[*record._select do |column, value| 
      column[/^#{klass.table_name}/]
    end.map do |column, value|
      [column[/\.(.*)/, 1], value]
    end.flatten]
              
    # allocate and assign values
    returning(klass.allocate) do |obj|
      obj.instance_variable_set("@attributes", record)
      obj.instance_variable_set("@attributes_cache", Hash.new)
      
      if obj.respond_to_without_attributes?(:after_find)
        obj.send(:callback, :after_find)
      end
      
      if obj.respond_to_without_attributes?(:after_initialize)
        obj.send(:callback, :after_initialize)
      end
      
    end
  else                       
    instantiate_without_polymorphic_checks(record)
  end
end

Instance Method Details

#_base_class_nameObject

Return the base class name as a string.



80
81
82
# File 'lib/has_many_polymorphs/support_methods.rb', line 80

def _base_class_name
  self.class.base_class.name.to_s
end

#original_method_missingObject



54
# File 'lib/has_many_polymorphs/debugging_tools.rb', line 54

alias :original_method_missing :method_missing