diff options
Diffstat (limited to 'activerecord/lib/active_record')
6 files changed, 46 insertions, 26 deletions
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 6c878f0f00..827b01c5ac 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -184,7 +184,7 @@ module ActiveRecord macro = join_part.reflection.macro if macro == :has_one - return if record.association_cache.key?(join_part.reflection.name) + return record.association(join_part.reflection.name).target if record.association_cache.key?(join_part.reflection.name) association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil? set_target_and_inverse(join_part, association, record) else diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 236681096b..17cf34cdf6 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -16,22 +16,16 @@ module ActiveRecord module ClassMethods protected - # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. - # This enhanced read method automatically converts the UTC time stored in the database to the time + # The enhanced read method automatically converts the UTC time stored in the database to the time # zone stored in Time.zone. - def internal_attribute_access_code(attr_name, cast_code) + def attribute_cast_code(attr_name) column = columns_hash[attr_name] if create_time_zone_conversion_attribute?(attr_name, column) - super(attr_name, "(v=#{column.type_cast_code('v')}) && #{cast_code}") - else - super - end - end + typecast = "v = #{super}" + time_zone_conversion = "v.acts_like?(:time) ? v.in_time_zone : v" - def attribute_cast_code(attr_name) - if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) - "(v.acts_like?(:time) ? v.in_time_zone : v)" + "((#{typecast}) && (#{time_zone_conversion}))" else super end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 3d55729318..9bc0023539 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2028,7 +2028,7 @@ MSG attribute_names.each do |name| if (column = column_for_attribute(name)) && (include_primary_key || !column.primary) - if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name)) + if include_readonly_attributes || !self.class.readonly_attributes.include?(name) value = if klass.serialized_attributes.include?(name) @attributes[name].serialized_value @@ -2043,6 +2043,7 @@ MSG end end end + attrs end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 7f5ddf77d6..4d2c80356d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -499,9 +499,14 @@ module ActiveRecord # Returns a table's primary key and belonging sequence. def pk_and_sequence_for(table) - execute_and_free("SHOW INDEX FROM #{quote_table_name(table)} WHERE Key_name = 'PRIMARY'", 'SCHEMA') do |result| - keys = each_hash(result).map { |row| row[:Column_name] } - keys.length == 1 ? [keys.first, nil] : nil + execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result| + create_table = each_hash(result).first[:"Create Table"] + if create_table.to_s =~ /PRIMARY KEY\s+\((.+)\)/ + keys = $1.split(",").map { |key| key.gsub(/`/, "") } + keys.length == 1 ? [keys.first, nil] : nil + else + nil + end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 0a0da0b5d3..386b3f7465 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -1,6 +1,6 @@ require 'active_record/connection_adapters/sqlite_adapter' -gem 'sqlite3', '~> 1.3.4' +gem 'sqlite3', '~> 1.3.5' require 'sqlite3' module ActiveRecord diff --git a/activerecord/lib/active_record/explain.rb b/activerecord/lib/active_record/explain.rb index 4d013f0ef4..abe6fff5d5 100644 --- a/activerecord/lib/active_record/explain.rb +++ b/activerecord/lib/active_record/explain.rb @@ -1,5 +1,5 @@ module ActiveRecord - module Explain # :nodoc: + module Explain # logging_query_plan calls could appear nested in the call stack. In # particular this happens when a relation fetches its records, since # that results in find_by_sql calls downwards. @@ -13,33 +13,34 @@ module ActiveRecord # whole. That is, the threshold is not checked against each individual # query, but against the duration of the entire block. This approach is # convenient for relations. - def logging_query_plan(&block) - if (t = auto_explain_threshold_in_seconds) && !Thread.current[LOGGING_QUERY_PLAN] + def logging_query_plan(&block) # :nodoc: + threshold = auto_explain_threshold_in_seconds + if threshold && !Thread.current[LOGGING_QUERY_PLAN] && !Thread.current[SILENCED] begin Thread.current[LOGGING_QUERY_PLAN] = true start = Time.now result, sqls, binds = collecting_sqls_for_explain(&block) - logger.warn(exec_explain(sqls, binds)) if Time.now - start > t + logger.warn(exec_explain(sqls, binds)) if Time.now - start > threshold result ensure Thread.current[LOGGING_QUERY_PLAN] = false end else - block.call + yield end end # SCHEMA queries cannot be EXPLAINed, also we do not want to run EXPLAIN on # our own EXPLAINs now matter how loopingly beautiful that would be. SKIP_EXPLAIN_FOR = %w(SCHEMA EXPLAIN) - def ignore_explain_notification?(payload) + def ignore_explain_notification?(payload) # :nodoc: payload[:exception] || SKIP_EXPLAIN_FOR.include?(payload[:name]) end # Collects all queries executed while the passed block runs. Returns an # array with three elements, the result of the block, the strings with the # queries, and their respective bindings. - def collecting_sqls_for_explain(&block) + def collecting_sqls_for_explain # :nodoc: sqls = [] binds = [] callback = lambda do |*args| @@ -52,7 +53,7 @@ module ActiveRecord result = nil ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do - result = block.call + result = yield end [result, sqls, binds] @@ -60,7 +61,7 @@ module ActiveRecord # Makes the adapter execute EXPLAIN for the given queries and bindings. # Returns a formatted string ready to be logged. - def exec_explain(sqls, binds) + def exec_explain(sqls, binds) # :nodoc: sqls.zip(binds).map do |sql, bind| [].tap do |msg| msg << "EXPLAIN for: #{sql}" @@ -72,5 +73,24 @@ module ActiveRecord end.join("\n") end.join("\n") end + + SILENCED = :silence_explain + + # Silences automatic EXPLAIN logging for the duration of the block. + # + # This has high priority, no EXPLAINs will be run even if downwards + # the threshold is set to 0. + # + # As the name of the method suggests this only applies to automatic + # EXPLAINs, manual calls to +ActiveRecord::Relation#explain+ run. + def silence_auto_explain + # Implemented as a flag rather that setting the threshold to nil + # because we should not depend on a value that may be changed + # downwards. + Thread.current[SILENCED] = true + yield + ensure + Thread.current[SILENCED] = false + end end end |