diff options
Diffstat (limited to 'activerecord/lib/active_record/core.rb')
-rw-r--r-- | activerecord/lib/active_record/core.rb | 69 |
1 files changed, 35 insertions, 34 deletions
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index a7aff9f724..1244bd6195 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -88,7 +88,6 @@ module ActiveRecord mattr_accessor :maintain_test_schema, instance_accessor: false class_attribute :default_connection_handler, instance_writer: false - class_attribute :find_by_statement_cache def self.connection_handler ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler @@ -107,20 +106,19 @@ module ActiveRecord super end - def initialize_find_by_cache - self.find_by_statement_cache = {}.extend(Mutex_m) + def initialize_find_by_cache # :nodoc: + @find_by_statement_cache = {}.extend(Mutex_m) end - def inherited(child_class) + def inherited(child_class) # :nodoc: + # initialize cache at class definition for thread safety child_class.initialize_find_by_cache super end - def find(*ids) + def find(*ids) # :nodoc: # We don't have cache keys for this stuff yet return super unless ids.length == 1 - # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5 - return super if ids.first.kind_of?(Symbol) return super if block_given? || primary_key.nil? || default_scopes.any? || @@ -136,14 +134,13 @@ module ActiveRecord Please pass the id of the object by calling `.id` MSG end + key = primary_key - s = find_by_statement_cache[key] || find_by_statement_cache.synchronize { - find_by_statement_cache[key] ||= StatementCache.create(connection) { |params| - where(key => params.bind).limit(1) - } + statement = cached_find_by_statement(key) { |params| + where(key => params.bind).limit(1) } - record = s.execute([id], self, connection).first + record = statement.execute([id], self, connection).first unless record raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}" end @@ -152,7 +149,7 @@ module ActiveRecord raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'" end - def find_by(*args) + def find_by(*args) # :nodoc: return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any? return super if default_scopes.any? @@ -165,19 +162,16 @@ module ActiveRecord # We can't cache Post.find_by(author: david) ...yet return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) } - key = hash.keys + keys = hash.keys - klass = self - s = find_by_statement_cache[key] || find_by_statement_cache.synchronize { - find_by_statement_cache[key] ||= StatementCache.create(connection) { |params| - wheres = key.each_with_object({}) { |param,o| - o[param] = params.bind - } - klass.where(wheres).limit(1) + statement = cached_find_by_statement(keys) { |params| + wheres = keys.each_with_object({}) { |param, o| + o[param] = params.bind } + where(wheres).limit(1) } begin - s.execute(hash.values, self, connection).first + statement.execute(hash.values, self, connection).first rescue TypeError => e raise ActiveRecord::StatementInvalid.new(e.message, e) rescue RangeError @@ -185,11 +179,11 @@ module ActiveRecord end end - def find_by!(*args) + def find_by!(*args) # :nodoc: find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}") end - def initialize_generated_modules + def initialize_generated_modules # :nodoc: generated_association_methods end @@ -210,7 +204,7 @@ module ActiveRecord elsif !connected? "#{super} (call '#{super}.connection' to establish a connection)" elsif table_exists? - attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', ' + attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', ' "#{super}(#{attr_list})" else "#{super}(Table doesn't exist)" @@ -251,6 +245,12 @@ module ActiveRecord private + def cached_find_by_statement(key, &block) # :nodoc: + @find_by_statement_cache[key] || @find_by_statement_cache.synchronize { + @find_by_statement_cache[key] ||= StatementCache.create(connection, &block) + } + end + def relation # :nodoc: relation = Relation.create(self, arel_table, predicate_builder) @@ -345,9 +345,6 @@ module ActiveRecord _run_initialize_callbacks - @aggregation_cache = {} - @association_cache = {} - @new_record = true @destroyed = false @@ -456,6 +453,7 @@ module ActiveRecord # Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record` # when pp is required. def pretty_print(pp) + return super if custom_inspect_method_defined? pp.object_address_group(self) do if defined?(@attributes) && @attributes column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? } @@ -481,16 +479,16 @@ module ActiveRecord Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access end + private + def set_transaction_state(state) # :nodoc: @transaction_state = state end def has_transactional_callbacks? # :nodoc: - !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_create_callbacks.empty? + !_rollback_callbacks.empty? || !_commit_callbacks.empty? end - private - # Updates the attributes on this particular ActiveRecord object so that # if it is associated with a transaction, then the state of the AR object # will be updated to reflect the current state of the transaction @@ -513,6 +511,8 @@ module ActiveRecord end def update_attributes_from_transaction_state(transaction_state, depth) + @reflects_state = [false] if depth == 0 + if transaction_state && transaction_state.finalized? && !has_transactional_callbacks? unless @reflects_state[depth] restore_transaction_record_state if transaction_state.rolledback? @@ -539,8 +539,6 @@ module ActiveRecord end def init_internals - @aggregation_cache = {} - @association_cache = {} @readonly = false @destroyed = false @marked_for_destruction = false @@ -549,7 +547,6 @@ module ActiveRecord @txn = nil @_start_transaction_state = {} @transaction_state = nil - @reflects_state = [false] end def initialize_internals_callback @@ -560,5 +557,9 @@ module ActiveRecord @attributes = @attributes.dup end end + + def custom_inspect_method_defined? + self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner + end end end |