diff options
Diffstat (limited to 'activerecord/lib/active_record')
11 files changed, 55 insertions, 45 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 38e7ba39d3..ceedf150e3 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -55,13 +55,16 @@ module ActiveRecord 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) + + primary_key = reflection.association_primary_key + records = klass.where(primary_key => ids).index_by do |r| + r.public_send(primary_key) end.values_at(*ids).compact + if records.size != ids.size - found_ids = records.map { |record| record.send(reflection.association_primary_key) } + found_ids = records.map { |record| record.public_send(primary_key) } not_found_ids = ids - found_ids - klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, reflection.association_primary_key, not_found_ids) + klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids) else replace(records) end diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 5ba03c555a..4915a37f06 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -116,18 +116,8 @@ module ActiveRecord @reflection_scope ||= reflection.scope_for(klass) end - def klass_scope - current_scope = klass.current_scope - - if current_scope && current_scope.empty_scope? - klass.unscoped - else - klass.default_scoped - end - end - def build_scope - scope = klass_scope + scope = klass.scope_for_association if reflection.type scope.where!(reflection.type => model.base_class.sti_name) diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index 76237c4a0c..cba565448f 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -15,7 +15,7 @@ module ActiveRecord def target_scope scope = super reflection.chain.drop(1).each do |reflection| - relation = reflection.klass.all + relation = reflection.klass.scope_for_association scope.merge!( relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load) ) diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 48d33e6744..c622df132e 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -62,12 +62,6 @@ module ActiveRecord clear_mutation_trackers end - def write_attribute_without_type_cast(attr_name, *) # :nodoc: - result = super - clear_attribute_change(attr_name) - result - end - def clear_attribute_changes(attr_names) # :nodoc: super attr_names.each do |attr_name| @@ -183,6 +177,11 @@ module ActiveRecord end private + def write_attribute_without_type_cast(attr_name, _) + result = super + clear_attribute_change(attr_name) + result + end def mutation_tracker unless defined?(@mutation_tracker) diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index acd47629dd..ebc2baed34 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -70,7 +70,7 @@ module ActiveRecord end decorate_attribute_type(attr_name, :serialize) do |type| - if type_incompatible_with_serialize?(type) + if type_incompatible_with_serialize?(type, class_name_or_coder) raise ColumnNotSerializableError.new(attr_name, type) end @@ -80,12 +80,9 @@ module ActiveRecord private - def type_incompatible_with_serialize?(type) - type.is_a?(ActiveRecord::Type::Json) || - ( - defined?(ActiveRecord::ConnectionAdapters::PostgreSQL) && - type.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array) - ) + def type_incompatible_with_serialize?(type, class_name) + type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON || + type.respond_to?(:type_cast_array, true) && class_name == ::Array end end end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index ef302fc0a0..4940e122f4 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -1065,6 +1065,10 @@ class ActiveRecord::FixtureSet::RenderContext # :nodoc: def get_binding binding() end + + def binary(path) + %(!!binary "#{Base64.strict_encode64(File.read(path))}") + end end end end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 7f1601805c..b847933b2e 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -221,13 +221,8 @@ module ActiveRecord end def klass_join_scope(table, predicate_builder) # :nodoc: - current_scope = klass.current_scope - - if current_scope && current_scope.empty_scope? - build_scope(table, predicate_builder) - else - klass.default_scoped(build_scope(table, predicate_builder)) - end + relation = build_scope(table, predicate_builder) + klass.scope_for_association(relation) end def constraints @@ -329,6 +324,10 @@ module ActiveRecord def join_pk(_) foreign_key end + + def primary_key(klass) + klass.primary_key || raise(UnknownPrimaryKey.new(klass)) + end end # Base class for AggregateReflection and AssociationReflection. Objects of @@ -697,10 +696,6 @@ module ActiveRecord def derive_join_table ModelSchema.derive_join_table_name active_record.table_name, klass.table_name end - - def primary_key(klass) - klass.primary_key || raise(UnknownPrimaryKey.new(klass)) - end end class HasManyReflection < AssociationReflection # :nodoc: @@ -715,6 +710,10 @@ module ActiveRecord Associations::HasManyAssociation end end + + def association_primary_key(klass = nil) + primary_key(klass || self.klass) + end end class HasOneReflection < AssociationReflection # :nodoc: @@ -1016,10 +1015,6 @@ module ActiveRecord end end - def primary_key(klass) - klass.primary_key || raise(UnknownPrimaryKey.new(klass)) - end - def inverse_name; delegate_reflection.send(:inverse_name); end def derive_class_name diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 141ad176ea..fa19c679cf 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -47,7 +47,12 @@ module ActiveRecord # handle from 10000 and beyond by setting the +:start+ and +:finish+ # option on each worker. # - # # Let's process from record 10_000 on. + # # In worker 1, let's process until 9999 records. + # Person.find_each(finish: 9_999) do |person| + # person.party_all_night! + # end + # + # # In worker 2, let's process from record 10_000 and onwards. # Person.find_each(start: 10_000) do |person| # person.party_all_night! # end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index d3b5be6bce..42d43224fa 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -259,6 +259,9 @@ module ActiveRecord column = aggregate_column(column_name) select_value = operation_over_aggregate_column(column, operation, distinct) + if operation == "sum" && distinct + select_value.distinct = true + end column_alias = select_value.alias column_alias ||= @klass.connection.column_name_for_operation(operation, select_value) diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb index 43cce19c1f..6fa096c1fe 100644 --- a/activerecord/lib/active_record/scoping/named.rb +++ b/activerecord/lib/active_record/scoping/named.rb @@ -31,6 +31,16 @@ module ActiveRecord end end + def scope_for_association(scope = relation) # :nodoc: + current_scope = self.current_scope + + if current_scope && current_scope.empty_scope? + scope + else + default_scoped(scope) + end + end + def default_scoped(scope = relation) # :nodoc: build_default_scope(scope) || scope end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 2677fade18..baeb653c61 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -8,6 +8,10 @@ module ActiveRecord raise ArgumentError, "#{options[:conditions]} was passed as :conditions but is not callable. " \ "Pass a callable instead: `conditions: -> { where(approved: true) }`" end + unless Array(options[:scope]).all? { |scope| scope.respond_to?(:to_sym) } + raise ArgumentError, "#{options[:scope]} is not supported format for :scope option. " \ + "Pass a symbol or an array of symbols instead: `scope: :user_id`" + end super({ case_sensitive: true }.merge!(options)) @klass = options[:class] end |