aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/associations')
-rw-r--r--activerecord/lib/active_record/associations/association.rb13
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb2
-rw-r--r--activerecord/lib/active_record/associations/builder/belongs_to.rb30
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb8
-rw-r--r--activerecord/lib/active_record/associations/builder/singular_association.rb11
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb73
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb29
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb12
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb15
-rw-r--r--activerecord/lib/active_record/associations/has_one_association.rb14
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb18
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb34
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb2
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb6
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb21
-rw-r--r--activerecord/lib/active_record/associations/through_association.rb4
16 files changed, 149 insertions, 143 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index f506614591..84d0493a60 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -112,6 +112,15 @@ module ActiveRecord
record
end
+ # Remove the inverse association, if possible
+ def remove_inverse_instance(record)
+ if invertible_for?(record)
+ inverse = record.association(inverse_reflection_for(record).name)
+ inverse.target = nil
+ inverse.inversed = false
+ end
+ end
+
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
# polymorphic_type field on the owner.
def klass
@@ -166,7 +175,7 @@ module ActiveRecord
def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
except_from_scope_attributes ||= {}
skip_assign = [reflection.foreign_key, reflection.type].compact
- assigned_keys = record.changed
+ assigned_keys = record.changed_attribute_names_to_save
assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
attributes = create_scope.except(*(assigned_keys - skip_assign))
record.assign_attributes(attributes)
@@ -254,7 +263,7 @@ module ActiveRecord
# so that when stale_state is different from the value stored on the last find_target,
# the target is stale.
#
- # This is only relevant to certain associations, which is why it returns nil by default.
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
def stale_state
end
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 12f8c1ccd4..c6d204d3c2 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -49,6 +49,8 @@ module ActiveRecord
binds
end
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
+ # Workaround for Ruby 2.2 "private attribute?" warning.
protected
attr_reader :value_transformation
diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb
index 3121e70a04..a1609ab0fb 100644
--- a/activerecord/lib/active_record/associations/builder/belongs_to.rb
+++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb
@@ -35,17 +35,17 @@ module ActiveRecord::Associations::Builder # :nodoc:
@_after_create_counter_called = false
elsif (@_after_replace_counter_called ||= false)
@_after_replace_counter_called = false
- elsif attribute_changed?(foreign_key) && !new_record?
+ elsif saved_change_to_attribute?(foreign_key) && !new_record?
if reflection.polymorphic?
- model = attribute(reflection.foreign_type).try(:constantize)
- model_was = attribute_was(reflection.foreign_type).try(:constantize)
+ model = attribute_in_database(reflection.foreign_type).try(:constantize)
+ model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
else
model = reflection.klass
model_was = reflection.klass
end
- foreign_key_was = attribute_was foreign_key
- foreign_key = attribute foreign_key
+ foreign_key_was = attribute_before_last_save foreign_key
+ foreign_key = attribute_in_database foreign_key
if foreign_key && model.respond_to?(:increment_counter)
model.increment_counter(cache_column, foreign_key)
@@ -70,14 +70,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
end
- def self.touch_record(o, foreign_key, name, touch, touch_method) # :nodoc:
- old_foreign_id = o.changed_attributes[foreign_key]
+ def self.touch_record(o, changes, foreign_key, name, touch, touch_method) # :nodoc:
+ old_foreign_id = changes[foreign_key] && changes[foreign_key].first
if old_foreign_id
association = o.association(name)
reflection = association.reflection
if reflection.polymorphic?
- klass = o.public_send("#{reflection.foreign_type}_was").constantize
+ foreign_type = reflection.foreign_type
+ klass = changes[foreign_type] && changes[foreign_type].first || o.public_send(foreign_type)
+ klass = klass.constantize
else
klass = association.klass
end
@@ -107,13 +109,13 @@ module ActiveRecord::Associations::Builder # :nodoc:
n = reflection.name
touch = reflection.options[:touch]
- callback = lambda { |record|
- BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
- }
+ callback = lambda { |changes_method| lambda { |record|
+ BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
+ }}
- model.after_save callback, if: :changed?
- model.after_touch callback
- model.after_destroy callback
+ model.after_save callback.(:saved_changes), if: :saved_changes?
+ model.after_touch callback.(:changes_to_save)
+ model.after_destroy callback.(:changes_to_save)
end
def self.add_destroy_callbacks(model, reflection)
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index 047292b2bd..6b71826431 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -28,7 +28,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
class_name = options.fetch(:class_name) {
name.to_s.camelize.singularize
}
- KnownClass.new lhs_class, class_name
+ KnownClass.new lhs_class, class_name.to_s
end
end
end
@@ -78,9 +78,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
private
- def self.suppress_composite_primary_key(pk)
- pk unless pk.is_a?(Array)
- end
+ def self.suppress_composite_primary_key(pk)
+ pk unless pk.is_a?(Array)
+ end
}
join_model.name = "HABTM_#{association_name.to_s.camelize}"
diff --git a/activerecord/lib/active_record/associations/builder/singular_association.rb b/activerecord/lib/active_record/associations/builder/singular_association.rb
index bb96202a22..7732b63af6 100644
--- a/activerecord/lib/active_record/associations/builder/singular_association.rb
+++ b/activerecord/lib/active_record/associations/builder/singular_association.rb
@@ -8,7 +8,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
def self.define_accessors(model, reflection)
super
- define_constructors(model.generated_association_methods, reflection.name) if reflection.constructable?
+ mixin = model.generated_association_methods
+ name = reflection.name
+
+ define_constructors(mixin, name) if reflection.constructable?
+
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def reload_#{name}
+ association(:#{name}).force_reload_reader
+ end
+ CODE
end
# Defines the (build|create)_association methods for belongs_to or has_one association
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 08bd532fb0..0437a79b84 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -25,16 +25,8 @@ module ActiveRecord
# +load_target+ and the +loaded+ flag are your friends.
class CollectionAssociation < Association #:nodoc:
# Implements the reader method, e.g. foo.items for Foo.has_many :items
- def reader(force_reload = false)
- if force_reload
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Passing an argument to force an association to reload is now
- deprecated and will be removed in Rails 5.1. Please call `reload`
- on the result collection proxy instead.
- MSG
-
- klass.uncached { reload }
- elsif stale_target?
+ def reader
+ if stale_target?
reload
end
@@ -55,9 +47,7 @@ module ActiveRecord
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
def ids_reader
if loaded?
- load_target.map do |record|
- record.send(reflection.association_primary_key)
- end
+ target.pluck(reflection.association_primary_key)
else
@association_ids ||= (
column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
@@ -68,13 +58,17 @@ module ActiveRecord
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
def ids_writer(ids)
- pk_type = reflection.primary_key_type
+ pk_type = reflection.association_primary_key_type
ids = Array(ids).reject(&:blank?)
ids.map! { |i| pk_type.cast(i) }
records = klass.where(reflection.association_primary_key => ids).index_by do |r|
r.send(reflection.association_primary_key)
- end.values_at(*ids)
- replace(records)
+ end.values_at(*ids).compact
+ if records.size != ids.size
+ klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, reflection.association_primary_key)
+ else
+ replace(records)
+ end
end
def reset
@@ -192,11 +186,8 @@ module ActiveRecord
# +delete_records+. They are in any case removed from the collection.
def delete(*records)
return if records.empty?
- _options = records.extract_options!
- dependent = _options[:dependent] || options[:dependent]
-
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
- delete_or_destroy(records, dependent)
+ delete_or_destroy(records, options[:dependent])
end
# Deletes the +records+ and removes them from this association calling
@@ -222,11 +213,7 @@ module ActiveRecord
# +count_records+, which is a method descendants have to provide.
def size
if !find_target? || loaded?
- if association_scope.distinct_value
- target.uniq.size
- else
- target.size
- end
+ target.size
elsif !association_scope.group_values.empty?
load_target.size
elsif !association_scope.distinct_value && target.is_a?(Array)
@@ -253,14 +240,6 @@ module ActiveRecord
end
end
- def distinct
- seen = {}
- load_target.find_all do |record|
- seen[record.id] = true unless seen.key?(record.id)
- end
- end
- alias uniq distinct
-
# Replace this collection with +other_array+. This will perform a diff
# and delete/add only records that have changed.
def replace(other_array)
@@ -310,19 +289,28 @@ module ActiveRecord
def replace_on_target(record, index, skip_callbacks)
callback(:before_add, record) unless skip_callbacks
- was_loaded = loaded?
- yield(record) if block_given?
+ begin
+ if index
+ record_was = target[index]
+ target[index] = record
+ else
+ target << record
+ end
+
+ set_inverse_instance(record)
- unless !was_loaded && loaded?
+ yield(record) if block_given?
+ rescue
if index
- @target[index] = record
+ target[index] = record_was
else
- @target << record
+ target.delete(record)
end
+
+ raise
end
callback(:after_add, record) unless skip_callbacks
- set_inverse_instance(record)
record
end
@@ -379,7 +367,7 @@ module ActiveRecord
persisted.map! do |record|
if mem_record = memory.delete(record)
- ((record.attribute_names & mem_record.attribute_names) - mem_record.changes.keys).each do |name|
+ ((record.attribute_names & mem_record.attribute_names) - mem_record.changed_attribute_names_to_save).each do |name|
mem_record[name] = record[name]
end
@@ -439,8 +427,9 @@ module ActiveRecord
records.each { |record| callback(:after_remove, record) }
end
- # Delete the given records from the association, using one of the methods :destroy,
- # :delete_all or :nullify (or nil, in which case a default is used).
+ # Delete the given records from the association,
+ # using one of the methods +:destroy+, +:delete_all+
+ # or +:nullify+ (or +nil+, in which case a default is used).
def delete_records(records, method)
raise NotImplementedError
end
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index dda240585e..0d84805b4d 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -106,12 +106,6 @@ module ActiveRecord
# # #<Pet id: 2, name: "Spook", person_id: 1>,
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
# # ]
- #
- # person.pets.select(:name) { |pet| pet.name =~ /oo/ }
- # # => [
- # # #<Pet id: 2, name: "Spook">,
- # # #<Pet id: 3, name: "Choo-Choo">
- # # ]
# Finds an object in the collection responding to the +id+. Uses the same
# rules as ActiveRecord::Base.find. Returns ActiveRecord::RecordNotFound
@@ -724,6 +718,12 @@ module ActiveRecord
@association.destroy(*records)
end
+ ##
+ # :method: distinct
+ #
+ # :call-seq:
+ # distinct(value = true)
+ #
# Specifies whether the records should be unique or not.
#
# class Person < ActiveRecord::Base
@@ -738,10 +738,17 @@ module ActiveRecord
#
# person.pets.select(:name).distinct
# # => [#<Pet name: "Fancy-Fancy">]
- def distinct
- @association.distinct
+ #
+ # person.pets.select(:name).distinct.distinct(false)
+ # # => [
+ # # #<Pet name: "Fancy-Fancy">,
+ # # #<Pet name: "Fancy-Fancy">
+ # # ]
+
+ #--
+ def uniq
+ load_target.uniq
end
- alias uniq distinct
def calculate(operation, column_name)
null_scope? ? scope.calculate(operation, column_name) : super
@@ -1119,7 +1126,7 @@ module ActiveRecord
self
end
- protected
+ private
def find_nth_with_limit(index, limit)
load_target if find_from_target?
@@ -1131,8 +1138,6 @@ module ActiveRecord
super
end
- private
-
def null_scope?
@association.null_scope?
end
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index d1d0cc4c49..25613d2fa7 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -16,14 +16,7 @@ module ActiveRecord
when :restrict_with_error
unless empty?
record = owner.class.human_attribute_name(reflection.name).downcase
- message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.many', record: record, raise: true) rescue nil
- if message
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
- The error key `:'restrict_dependent_destroy.many'` has been deprecated and will be removed in Rails 5.1.
- Please use `:'restrict_dependent_destroy.has_many'` instead.
- MESSAGE
- end
- owner.errors.add(:base, message || :'restrict_dependent_destroy.has_many', record: record)
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
throw(:abort)
end
@@ -38,7 +31,6 @@ module ActiveRecord
def insert_record(record, validate = true, raise = false)
set_owner_attributes(record)
- set_inverse_instance(record)
if raise
record.save!(validate: validate)
@@ -72,7 +64,7 @@ module ActiveRecord
# the loaded flag is set to true as well.
def count_records
count = if reflection.has_cached_counter?
- owner._read_attribute reflection.counter_cache_column
+ owner._read_attribute(reflection.counter_cache_column).to_i
else
scope.count
end
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index d258eac0ed..c4a7fe4432 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -38,10 +38,12 @@ module ActiveRecord
def insert_record(record, validate = true, raise = false)
ensure_not_nested
- if raise
- record.save!(validate: validate)
- else
- return unless record.save(validate: validate)
+ if record.new_record? || record.has_changes_to_save?
+ if raise
+ record.save!(validate: validate)
+ else
+ return unless record.save(validate: validate)
+ end
end
save_through_record(record)
@@ -86,7 +88,10 @@ module ActiveRecord
end
def save_through_record(record)
- build_through_record(record).save!
+ association = build_through_record(record)
+ if association.changed?
+ association.save!
+ end
ensure
@through_records.delete(record.object_id)
end
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index 5ea9577301..b624154def 100644
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
@@ -12,14 +12,7 @@ module ActiveRecord
when :restrict_with_error
if load_target
record = owner.class.human_attribute_name(reflection.name).downcase
- message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.one', record: record, raise: true) rescue nil
- if message
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
- The error key `:'restrict_dependent_destroy.one'` has been deprecated and will be removed in Rails 5.1.
- Please use `:'restrict_dependent_destroy.has_one'` instead.
- MESSAGE
- end
- owner.errors.add(:base, message || :'restrict_dependent_destroy.has_one', record: record)
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_one', record: record)
throw(:abort)
end
@@ -35,7 +28,7 @@ module ActiveRecord
return target unless target || record
assigning_another_record = target != record
- if assigning_another_record || record.changed?
+ if assigning_another_record || record.has_changes_to_save?
save &&= owner.persisted?
transaction_if(save) do
@@ -86,8 +79,9 @@ module ActiveRecord
target.delete
when :destroy
target.destroy
- else
+ else
nullify_owner_attributes(target)
+ remove_inverse_instance(target)
if target.persisted? && owner.persisted? && !target.save
set_owner_attributes(target)
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index c26c469c1e..4cd1e64c3d 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -7,12 +7,12 @@ module ActiveRecord
class Aliases # :nodoc:
def initialize(tables)
@tables = tables
- @alias_cache = tables.each_with_object({}) { |table,h|
- h[table.node] = table.columns.each_with_object({}) { |column,i|
+ @alias_cache = tables.each_with_object({}) { |table, h|
+ h[table.node] = table.columns.each_with_object({}) { |column, i|
i[column.name] = column.alias
}
}
- @name_and_alias_cache = tables.each_with_object({}) { |table,h|
+ @name_and_alias_cache = tables.each_with_object({}) { |table, h|
h[table.node] = table.columns.map { |column|
[column.name, column.alias]
}
@@ -62,7 +62,7 @@ module ActiveRecord
walk_tree assoc, hash
end
when Hash
- associations.each do |k,v|
+ associations.each do |k, v|
cache = hash[k] ||= {}
walk_tree v, cache
end
@@ -126,8 +126,8 @@ module ActiveRecord
end
def aliases
- Aliases.new join_root.each_with_index.map { |join_part,i|
- columns = join_part.column_names.each_with_index.map { |column_name,j|
+ Aliases.new join_root.each_with_index.map { |join_part, i|
+ columns = join_part.column_names.each_with_index.map { |column_name, j|
Aliases::Column.new column_name, "t#{i}_r#{j}"
}
Aliases::Table.new(join_part, columns)
@@ -143,7 +143,7 @@ module ActiveRecord
}
}
- model_cache = Hash.new { |h,klass| h[klass] = {} }
+ model_cache = Hash.new { |h, klass| h[klass] = {} }
parents = model_cache[join_root]
column_aliases = aliases.column_aliases join_root
@@ -223,8 +223,8 @@ module ActiveRecord
[left.children.find { |node2| node1.match? node2 }, node1]
}.partition(&:first)
- ojs = missing.flat_map { |_,n| make_outer_joins left, n }
- intersection.flat_map { |l,r| walk l, r }.concat ojs
+ ojs = missing.flat_map { |_, n| make_outer_joins left, n }
+ intersection.flat_map { |l, r| walk l, r }.concat ojs
end
def find_reflection(klass, name)
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index a81860e40f..9f77f38b35 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -106,7 +106,7 @@ module ActiveRecord
private
- # Loads all the given data into +records+ for the +association+.
+ # Loads all the given data into +records+ for the +association+.
def preloaders_on(association, records, scope)
case association
when Hash
@@ -132,18 +132,18 @@ module ActiveRecord
}
end
- # Loads all the given data into +records+ for a singular +association+.
- #
- # Functions by instantiating a preloader class such as Preloader::HasManyThrough and
- # call the +run+ method for each passed in class in the +records+ argument.
- #
- # Not all records have the same class, so group then preload group on the reflection
- # itself so that if various subclass share the same association then we do not split
- # them unnecessarily
- #
- # Additionally, polymorphic belongs_to associations can have multiple associated
- # classes, depending on the polymorphic_type field. So we group by the classes as
- # well.
+ # Loads all the given data into +records+ for a singular +association+.
+ #
+ # Functions by instantiating a preloader class such as Preloader::HasManyThrough and
+ # call the +run+ method for each passed in class in the +records+ argument.
+ #
+ # Not all records have the same class, so group then preload group on the reflection
+ # itself so that if various subclass share the same association then we do not split
+ # them unnecessarily
+ #
+ # Additionally, polymorphic belongs_to associations can have multiple associated
+ # classes, depending on the polymorphic_type field. So we group by the classes as
+ # well.
def preloaders_for_one(association, records, scope)
grouped_records(association, records).flat_map do |reflection, klasses|
klasses.map do |rhs_klass, rs|
@@ -187,10 +187,10 @@ module ActiveRecord
def self.owners; []; end
end
- # Returns a class containing the logic needed to load preload the data
- # and attach it to a relation. For example +Preloader::Association+ or
- # +Preloader::HasManyThrough+. The class returned implements a `run` method
- # that accepts a preloader.
+ # Returns a class containing the logic needed to load preload the data
+ # and attach it to a relation. For example +Preloader::Association+ or
+ # +Preloader::HasManyThrough+. The class returned implements a `run` method
+ # that accepts a preloader.
def preloader_for(reflection, owners, rhs_klass)
return NullPreloader unless rhs_klass
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index c79efca920..4072d19380 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -113,7 +113,7 @@ module ActiveRecord
return {} if owner_keys.empty?
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
# Make several smaller queries if necessary or make one query if the adapter supports it
- slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
+ slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
@preloaded_records = slices.flat_map do |slice|
records_for(slice).load(&block)
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index be9dfe7686..9d44a02021 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -24,7 +24,7 @@ module ActiveRecord
reset_association owners, through_reflection.name
- middle_records = through_records.flat_map { |(_,rec)| rec }
+ middle_records = through_records.flat_map { |(_, rec)| rec }
preloaders = preloader.preload(middle_records,
source_reflection.name,
@@ -32,13 +32,13 @@ module ActiveRecord
@preloaded_records = preloaders.flat_map(&:preloaded_records)
- middle_to_pl = preloaders.each_with_object({}) do |pl,h|
+ middle_to_pl = preloaders.each_with_object({}) do |pl, h|
pl.owners.each { |middle|
h[middle] = pl
}
end
- through_records.each_with_object({}) do |(lhs,center), records_by_owner|
+ through_records.each_with_object({}) do |(lhs, center), records_by_owner|
pl_to_middle = center.group_by { |record| middle_to_pl[record] }
records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index e386cc0e4c..91580a28d0 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -2,16 +2,8 @@ module ActiveRecord
module Associations
class SingularAssociation < Association #:nodoc:
# Implements the reader method, e.g. foo.bar for Foo.has_one :bar
- def reader(force_reload = false)
- if force_reload && klass
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Passing an argument to force an association to reload is now
- deprecated and will be removed in Rails 5.1. Please call `reload`
- on the parent object instead.
- MSG
-
- klass.uncached { reload }
- elsif !loaded? || stale_target?
+ def reader
+ if !loaded? || stale_target?
reload
end
@@ -30,6 +22,13 @@ module ActiveRecord
record
end
+ # Implements the reload reader method, e.g. foo.reload_bar for
+ # Foo.has_one :bar
+ def force_reload_reader
+ klass.uncached { reload }
+ target
+ end
+
private
def create_scope
@@ -51,6 +50,8 @@ module ActiveRecord
sc.execute(binds, klass, conn) do |record|
set_inverse_instance record
end.first
+ rescue ::RangeError
+ nil
end
def replace(record)
diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index f4129edc5a..6b87993ba3 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -4,7 +4,7 @@ module ActiveRecord
module ThroughAssociation #:nodoc:
delegate :source_reflection, :through_reflection, to: :reflection
- protected
+ private
# We merge in these scopes for two reasons:
#
@@ -21,8 +21,6 @@ module ActiveRecord
scope
end
- private
-
# Construct attributes for :through pointing to owner and associate. This is used by the
# methods which create and delete records on the association.
#