diff options
Diffstat (limited to 'activerecord/lib/active_record')
4 files changed, 42 insertions, 14 deletions
diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index ac387d377d..e8e36e7cd0 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -91,7 +91,13 @@ module ActiveRecord::Associations::Builder old_foreign_id = o.changed_attributes[foreign_key] if old_foreign_id - klass = o.association(name).klass + association = o.association(name) + reflection = association.reflection + if reflection.polymorphic? + klass = o.public_send("#{reflection.foreign_type}_was").constantize + else + klass = association.klass + end old_record = klass.find_by(klass.primary_key => old_foreign_id) if old_record diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 3924eec872..217fc52dd5 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -128,6 +128,16 @@ module ActiveRecord end end + def find_generated_attribute_method(method_name) # :nodoc: + klass = self + until klass == Base + gen_methods = klass.generated_attribute_methods + return gen_methods.instance_method(method_name) if method_defined_within?(method_name, gen_methods, Object) + klass = klass.superclass + end + nil + end + # Returns +true+ if +attribute+ is an attribute method and table exists, # +false+ otherwise. # @@ -163,7 +173,14 @@ module ActiveRecord def method_missing(method, *args, &block) # :nodoc: self.class.define_attribute_methods if respond_to_without_attributes?(method) - send(method, *args, &block) + # make sure to invoke the correct attribute method, as we might have gotten here via a `super` + # call in a overwritten attribute method + if attribute_method = self.class.find_generated_attribute_method(method) + # this is probably horribly slow, but should only happen at most once for a given AR class + attribute_method.bind(self).call(*args, &block) + else + send(method, *args, &block) + end else super end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 5dc70a5ad1..571257f6dd 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -172,7 +172,7 @@ module ActiveRecord def columns(table_name) # Limit, precision, and scale are all handled by the superclass. column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod| - oid = OID::TYPE_MAP.fetch(oid.to_i, fmod.to_i) { + oid = type_map.fetch(oid.to_i, fmod.to_i) { OID::Identity.new } PostgreSQLColumn.new(column_name, default, oid, type, notnull == 'f') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index adeb57d913..1ec1490263 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -565,7 +565,8 @@ module ActiveRecord raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!" end - initialize_type_map + @type_map = OID::TypeMap.new + initialize_type_map(type_map) @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true end @@ -738,39 +739,43 @@ module ActiveRecord private + def type_map + @type_map + end + def reload_type_map - OID::TYPE_MAP.clear - initialize_type_map + type_map.clear + initialize_type_map(type_map) end - def initialize_type_map + def initialize_type_map(type_map) result = execute('SELECT oid, typname, typelem, typdelim, typinput FROM pg_type', 'SCHEMA') leaves, nodes = result.partition { |row| row['typelem'] == '0' } # populate the leaf nodes leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row| - OID::TYPE_MAP[row['oid'].to_i] = OID::NAMES[row['typname']] + type_map[row['oid'].to_i] = OID::NAMES[row['typname']] end arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' } # populate composite types - nodes.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row| + nodes.find_all { |row| type_map.key? row['typelem'].to_i }.each do |row| if OID.registered_type? row['typname'] # this composite type is explicitly registered vector = OID::NAMES[row['typname']] else # use the default for composite types - vector = OID::Vector.new row['typdelim'], OID::TYPE_MAP[row['typelem'].to_i] + vector = OID::Vector.new row['typdelim'], type_map[row['typelem'].to_i] end - OID::TYPE_MAP[row['oid'].to_i] = vector + type_map[row['oid'].to_i] = vector end # populate array types - arrays.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row| - array = OID::Array.new OID::TYPE_MAP[row['typelem'].to_i] - OID::TYPE_MAP[row['oid'].to_i] = array + arrays.find_all { |row| type_map.key? row['typelem'].to_i }.each do |row| + array = OID::Array.new type_map[row['typelem'].to_i] + type_map[row['oid'].to_i] = array end end |