aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/associations/association.rb8
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb29
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb4
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb1
-rw-r--r--activerecord/lib/active_record/attribute_set.rb2
-rw-r--r--activerecord/lib/active_record/autosave_association.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/enum.rb23
-rw-r--r--activerecord/lib/active_record/inheritance.rb2
-rw-r--r--activerecord/lib/active_record/integration.rb73
-rw-r--r--activerecord/lib/active_record/model_schema.rb28
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb2
-rw-r--r--activerecord/lib/active_record/relation.rb9
-rw-r--r--activerecord/lib/active_record/relation/batches.rb24
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb18
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb8
-rw-r--r--activerecord/lib/active_record/scoping/named.rb12
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb6
22 files changed, 153 insertions, 124 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 1cb2b2d7c6..6b13e6936f 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -152,14 +152,6 @@ module ActiveRecord
reset
end
- def interpolate(sql, record = nil)
- if sql.respond_to?(:to_proc)
- owner.instance_exec(record, &sql)
- else
- sql
- end
- end
-
# We can't dump @reflection since it contains the scope proc
def marshal_dump
ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 8995b1e352..643226267c 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -106,12 +106,7 @@ module ActiveRecord
def join_constraints(outer_joins, join_type)
joins = join_root.children.flat_map { |child|
-
- if join_type == Arel::Nodes::OuterJoin
- make_left_outer_joins join_root, child
- else
- make_inner_joins join_root, child
- end
+ make_join_constraints(join_root, child, join_type)
}
joins.concat outer_joins.flat_map { |oj|
@@ -175,27 +170,15 @@ module ActiveRecord
end
def make_outer_joins(parent, child)
- tables = table_aliases_for(parent, child)
- join_type = Arel::Nodes::OuterJoin
- info = make_constraints parent, child, tables, join_type
-
- [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
- end
-
- def make_left_outer_joins(parent, child)
- tables = child.tables
join_type = Arel::Nodes::OuterJoin
- info = make_constraints parent, child, tables, join_type
-
- [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
+ make_join_constraints(parent, child, join_type, true)
end
- def make_inner_joins(parent, child)
- tables = child.tables
- join_type = Arel::Nodes::InnerJoin
- info = make_constraints parent, child, tables, join_type
+ def make_join_constraints(parent, child, join_type, aliasing = false)
+ tables = aliasing ? table_aliases_for(parent, child) : child.tables
+ info = make_constraints(parent, child, tables, join_type)
- [info] + child.children.flat_map { |c| make_inner_joins(child, c) }
+ [info] + child.children.flat_map { |c| make_join_constraints(child, c, join_type, aliasing) }
end
def table_aliases_for(parent, node)
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
index 61cec5403a..80c9fde5d1 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -22,10 +22,6 @@ module ActiveRecord
@children = children
end
- def name
- reflection.name
- end
-
def match?(other)
self.class == other.class
end
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index ebe06566cc..83c61fad19 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -62,7 +62,6 @@ module ActiveRecord
super(attribute_names)
@attribute_methods_generated = true
end
- true
end
def undefine_attribute_methods # :nodoc:
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index 66b278219a..01f9d815d5 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -64,7 +64,7 @@ module ActiveRecord
end
def deep_dup
- dup.tap do |copy|
+ self.class.allocate.tap do |copy|
copy.instance_variable_set(:@attributes, attributes.deep_dup)
end
end
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 607c54e481..829a4f6e86 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -216,13 +216,7 @@ module ActiveRecord
method = :validate_single_association
end
- define_non_cyclic_method(validation_method) do
- send(method, reflection)
- # TODO: remove the following line as soon as the return value of
- # callbacks is ignored, that is, returning `false` does not
- # display a deprecation warning or halts the callback chain.
- true
- end
+ define_non_cyclic_method(validation_method) { send(method, reflection) }
validate validation_method
after_validation :_ensure_no_duplicate_errors
end
@@ -369,7 +363,6 @@ module ActiveRecord
# association whether or not the parent was a new record before saving.
def before_save_collection_association
@new_record_before_save = new_record?
- true
end
def after_save_collection_association
@@ -389,7 +382,7 @@ module ActiveRecord
autosave = reflection.options[:autosave]
# reconstruct the scope now that we know the owner's id
- association.reset_scope if association.respond_to?(:reset_scope)
+ association.reset_scope
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
if autosave
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 46d7f84efd..a30fbe0e05 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -146,7 +146,7 @@ module ActiveRecord
end
def polymorphic_options
- as_options(polymorphic)
+ as_options(polymorphic).merge(null: options[:null])
end
def index_options
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 13629dee7f..16a398f631 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1280,9 +1280,10 @@ module ActiveRecord
end
def foreign_key_name(table_name, options)
- identifier = "#{table_name}_#{options.fetch(:column)}_fk"
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
options.fetch(:name) do
+ identifier = "#{table_name}_#{options.fetch(:column)}_fk"
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
+
"fk_rails_#{hashed_identifier}"
end
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 5b483ad4ab..3eff9e2f83 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -186,17 +186,17 @@ module ActiveRecord
# Returns the current database encoding format.
def encoding
- select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA")
+ select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database()", "SCHEMA")
end
# Returns the current database collation.
def collation
- select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA")
+ select_value("SELECT datcollate FROM pg_database WHERE datname = current_database()", "SCHEMA")
end
# Returns the current database ctype.
def ctype
- select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA")
+ select_value("SELECT datctype FROM pg_database WHERE datname = current_database()", "SCHEMA")
end
# Returns an array of schema names.
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 0ab03b2ab3..496abfc5d9 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -154,11 +154,12 @@ module ActiveRecord
definitions.each do |name, values|
# statuses = { }
enum_values = ActiveSupport::HashWithIndifferentAccess.new
- name = name.to_sym
+ name = name.to_s
# def self.statuses() statuses end
- detect_enum_conflict!(name, name.to_s.pluralize, true)
- klass.singleton_class.send(:define_method, name.to_s.pluralize) { enum_values }
+ detect_enum_conflict!(name, name.pluralize, true)
+ singleton_class.send(:define_method, name.pluralize) { enum_values }
+ defined_enums[name] = enum_values
detect_enum_conflict!(name, name)
detect_enum_conflict!(name, "#{name}=")
@@ -170,7 +171,7 @@ module ActiveRecord
_enum_methods_module.module_eval do
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
- pairs.each do |value, i|
+ pairs.each do |label, value|
if enum_prefix == true
prefix = "#{name}_"
elsif enum_prefix
@@ -182,23 +183,23 @@ module ActiveRecord
suffix = "_#{enum_suffix}"
end
- value_method_name = "#{prefix}#{value}#{suffix}"
- enum_values[value] = i
+ value_method_name = "#{prefix}#{label}#{suffix}"
+ enum_values[label] = value
+ label = label.to_s
- # def active?() status == 0 end
+ # def active?() status == "active" end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
- define_method("#{value_method_name}?") { self[attr] == value.to_s }
+ define_method("#{value_method_name}?") { self[attr] == label }
- # def active!() update! status: :active end
+ # def active!() update!(status: 0) end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
define_method("#{value_method_name}!") { update!(attr => value) }
- # scope :active, -> { where status: 0 }
+ # scope :active, -> { where(status: 0) }
klass.send(:detect_enum_conflict!, name, value_method_name, true)
klass.scope value_method_name, -> { where(attr => value) }
end
end
- defined_enums[name.to_s] = enum_values
end
end
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index fbdaeaae51..236a65eba7 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -217,7 +217,7 @@ module ActiveRecord
def subclass_from_attributes(attrs)
attrs = attrs.to_h if attrs.respond_to?(:permitted?)
if attrs.is_a?(Hash)
- subclass_name = attrs.with_indifferent_access[inheritance_column]
+ subclass_name = attrs[inheritance_column] || attrs[inheritance_column.to_sym]
if subclass_name.present?
find_sti_class(subclass_name)
diff --git a/activerecord/lib/active_record/integration.rb b/activerecord/lib/active_record/integration.rb
index 8e71b60b29..32362fa86f 100644
--- a/activerecord/lib/active_record/integration.rb
+++ b/activerecord/lib/active_record/integration.rb
@@ -7,12 +7,21 @@ module ActiveRecord
included do
##
# :singleton-method:
- # Indicates the format used to generate the timestamp in the cache key.
- # Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
+ # Indicates the format used to generate the timestamp in the cache key, if
+ # versioning is off. Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
#
# This is +:usec+, by default.
class_attribute :cache_timestamp_format, instance_writer: false
self.cache_timestamp_format = :usec
+
+ ##
+ # :singleton-method:
+ # Indicates whether to use a stable #cache_key method that is accompanied
+ # by a changing version in the #cache_version method.
+ #
+ # This is +false+, by default until Rails 6.0.
+ class_attribute :cache_versioning, instance_writer: false
+ self.cache_versioning = false
end
# Returns a +String+, which Action Pack uses for constructing a URL to this
@@ -42,35 +51,65 @@ module ActiveRecord
id && id.to_s # Be sure to stringify the id for routes
end
- # Returns a cache key that can be used to identify this record.
+ # Returns a stable cache key that can be used to identify this record.
#
# Product.new.cache_key # => "products/new"
- # Product.find(5).cache_key # => "products/5" (updated_at not available)
- # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
+ # Product.find(5).cache_key # => "products/5"
#
- # You can also pass a list of named timestamps, and the newest in the list will be
- # used to generate the key:
+ # If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
+ # the cache key will also include a version.
#
- # Person.find(5).cache_key(:updated_at, :last_reviewed_at)
+ # Product.cache_versioning = false
+ # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
def cache_key(*timestamp_names)
if new_record?
"#{model_name.cache_key}/new"
else
- timestamp = if timestamp_names.any?
- max_updated_column_timestamp(timestamp_names)
+ if cache_version && timestamp_names.none?
+ "#{model_name.cache_key}/#{id}"
else
- max_updated_column_timestamp
- end
+ timestamp = if timestamp_names.any?
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Specifying a timestamp name for #cache_key has been deprecated in favor of
+ the explicit #cache_version method that can be overwritten.
+ MSG
- if timestamp
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
- "#{model_name.cache_key}/#{id}-#{timestamp}"
- else
- "#{model_name.cache_key}/#{id}"
+ max_updated_column_timestamp(timestamp_names)
+ else
+ max_updated_column_timestamp
+ end
+
+ if timestamp
+ timestamp = timestamp.utc.to_s(cache_timestamp_format)
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
+ else
+ "#{model_name.cache_key}/#{id}"
+ end
end
end
end
+ # Returns a cache version that can be used together with the cache key to form
+ # a recyclable caching scheme. By default, the #updated_at column is used for the
+ # cache_version, but this method can be overwritten to return something else.
+ #
+ # Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
+ # +false+ (which it is by default until Rails 6.0).
+ def cache_version
+ if cache_versioning && timestamp = try(:updated_at)
+ timestamp.utc.to_s(:usec)
+ end
+ end
+
+ # Returns a cache key along with the version.
+ def cache_key_with_version
+ if version = cache_version
+ "#{cache_key}-#{version}"
+ else
+ cache_key
+ end
+ end
+
module ClassMethods
# Defines your model's +to_param+ method to generate "pretty" URLs
# using +method_name+, which can be any attribute or method that
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 54216caaaf..013562708c 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -1,3 +1,5 @@
+require "monitor"
+
module ActiveRecord
module ModelSchema
extend ActiveSupport::Concern
@@ -152,6 +154,8 @@ module ActiveRecord
self.inheritance_column = "type"
delegate :type_for_attribute, to: :class
+
+ initialize_load_schema_monitor
end
# Derives the join table name for +first_table+ and +second_table+. The
@@ -377,7 +381,7 @@ module ActiveRecord
# default values when instantiating the Active Record object for this table.
def column_defaults
load_schema
- _default_attributes.to_hash
+ @column_defaults ||= _default_attributes.to_hash
end
def _default_attributes # :nodoc:
@@ -435,15 +439,27 @@ module ActiveRecord
initialize_find_by_cache
end
+ protected
+
+ def initialize_load_schema_monitor
+ @load_schema_monitor = Monitor.new
+ end
+
private
+ def inherited(child_class)
+ super
+ child_class.initialize_load_schema_monitor
+ end
+
def schema_loaded?
- defined?(@columns_hash) && @columns_hash
+ defined?(@schema_loaded) && @schema_loaded
end
def load_schema
- unless schema_loaded?
- load_schema!
+ return if schema_loaded?
+ @load_schema_monitor.synchronize do
+ load_schema! unless defined?(@columns_hash) && @columns_hash
end
end
@@ -457,6 +473,8 @@ module ActiveRecord
user_provided_default: false
)
end
+
+ @schema_loaded = true
end
def reload_schema_from_cache
@@ -466,10 +484,12 @@ module ActiveRecord
@attribute_types = nil
@content_columns = nil
@default_attributes = nil
+ @column_defaults = nil
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
@attributes_builder = nil
@columns = nil
@columns_hash = nil
+ @schema_loaded = false
@attribute_names = nil
@yaml_encoder = nil
direct_descendants.each do |descendant|
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 01ecd79b8f..3f39fb84e8 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -458,7 +458,7 @@ module ActiveRecord
end
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
- raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
+ raise ArgumentError, "Hash or Array expected for attribute `#{association_name}`, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
end
check_record_limit!(options[:limit], attributes_collection)
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 1a9e0a4a40..65fdbc2fe4 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -199,7 +199,7 @@ module ActiveRecord
def klass_join_scope(table, predicate_builder) # :nodoc:
if klass.current_scope
klass.current_scope.clone.tap { |scope|
- scope.joins_values = []
+ scope.joins_values = scope.left_outer_joins_values = [].freeze
}
else
relation = ActiveRecord::Relation.create(
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 333ad16e11..7a8f9abb36 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -2,7 +2,7 @@ module ActiveRecord
# = Active Record \Relation
class Relation
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
- :order, :joins, :left_joins, :left_outer_joins, :references,
+ :order, :joins, :left_outer_joins, :references,
:extending, :unscope]
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
@@ -18,6 +18,7 @@ module ActiveRecord
attr_reader :table, :klass, :loaded, :predicate_builder
alias :model :klass
alias :loaded? :loaded
+ alias :locked? :locked
def initialize(klass, table, predicate_builder, values = {})
@klass = klass
@@ -403,9 +404,9 @@ module ActiveRecord
#
# Note: Updating a large number of records will run an
# UPDATE query for each record, which may cause a performance
- # issue. So if it is not needed to run callbacks for each update, it is
- # preferred to use #update_all for updating all records using
- # a single query.
+ # issue. When running callbacks is not needed for each record update,
+ # it is preferred to use #update_all for updating all records
+ # in a single query.
def update(id = :all, attributes)
if id.is_a?(Array)
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index 76031515fd..13a2c3f511 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -30,14 +30,14 @@ module ActiveRecord
# end
#
# ==== Options
- # * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000.
+ # * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
- # an order is present in the relation.
+ # an order is present in the relation.
#
# Limits are honored, and if present there is no requirement for the batch
- # size, it can be less than, equal, or greater than the limit.
+ # size: it can be less than, equal to, or greater than the limit.
#
# The options +start+ and +finish+ are especially useful if you want
# multiple workers dealing with the same processing queue. You can make
@@ -89,14 +89,14 @@ module ActiveRecord
# To be yielded each record one by one, use #find_each instead.
#
# ==== Options
- # * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000.
+ # * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
- # an order is present in the relation.
+ # an order is present in the relation.
#
# Limits are honored, and if present there is no requirement for the batch
- # size, it can be less than, equal, or greater than the limit.
+ # size: it can be less than, equal to, or greater than the limit.
#
# The options +start+ and +finish+ are especially useful if you want
# multiple workers dealing with the same processing queue. You can make
@@ -140,9 +140,9 @@ module ActiveRecord
# If you do not provide a block to #in_batches, it will return a
# BatchEnumerator which is enumerable.
#
- # Person.in_batches.with_index do |relation, batch_index|
+ # Person.in_batches.each_with_index do |relation, batch_index|
# puts "Processing relation ##{batch_index}"
- # relation.each { |relation| relation.delete_all }
+ # relation.delete_all
# end
#
# Examples of calling methods on the returned BatchEnumerator object:
@@ -152,12 +152,12 @@ module ActiveRecord
# Person.in_batches.each_record(&:party_all_night!)
#
# ==== Options
- # * <tt>:of</tt> - Specifies the size of the batch. Default to 1000.
- # * <tt>:load</tt> - Specifies if the relation should be loaded. Default to false.
+ # * <tt>:of</tt> - Specifies the size of the batch. Defaults to 1000.
+ # * <tt>:load</tt> - Specifies if the relation should be loaded. Defaults to false.
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
- # an order is present in the relation.
+ # an order is present in the relation.
#
# Limits are honored, and if present there is no requirement for the batch
# size, it can be less than, equal, or greater than the limit.
@@ -186,7 +186,7 @@ module ActiveRecord
#
# NOTE: It's not possible to set the order. That is automatically set to
# ascending on the primary key ("id ASC") to make the batch ordering
- # consistent. Therefore the primary key must be orderable, e.g an integer
+ # consistent. Therefore the primary key must be orderable, e.g. an integer
# or a string.
#
# NOTE: By its nature, batch processing is subject to race conditions if
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index 257ae04ff4..4f739a0415 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -46,6 +46,8 @@ module ActiveRecord
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
:connection, :columns_hash, to: :klass
+ delegate :ast, :locked, to: :arel
+
module ClassSpecificRelation # :nodoc:
extend ActiveSupport::Concern
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 183fe91c05..a6309e0b5c 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -1,12 +1,3 @@
-require "active_record/relation/predicate_builder/array_handler"
-require "active_record/relation/predicate_builder/base_handler"
-require "active_record/relation/predicate_builder/basic_object_handler"
-require "active_record/relation/predicate_builder/range_handler"
-require "active_record/relation/predicate_builder/relation_handler"
-
-require "active_record/relation/predicate_builder/association_query_value"
-require "active_record/relation/predicate_builder/polymorphic_array_value"
-
module ActiveRecord
class PredicateBuilder # :nodoc:
delegate :resolve_column_aliases, to: :table
@@ -178,3 +169,12 @@ module ActiveRecord
end
end
end
+
+require "active_record/relation/predicate_builder/array_handler"
+require "active_record/relation/predicate_builder/base_handler"
+require "active_record/relation/predicate_builder/basic_object_handler"
+require "active_record/relation/predicate_builder/range_handler"
+require "active_record/relation/predicate_builder/relation_handler"
+
+require "active_record/relation/predicate_builder/association_query_value"
+require "active_record/relation/predicate_builder/polymorphic_array_value"
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 76e529f2de..79e65baae5 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1100,14 +1100,16 @@ module ActiveRecord
end
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
- "asc", "desc", "ASC", "DESC"] # :nodoc:
+ "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
def validate_order_args(args)
args.each do |arg|
next unless arg.is_a?(Hash)
arg.each do |_key, value|
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
+ unless VALID_DIRECTIONS.include?(value)
+ raise ArgumentError,
+ "Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
+ end
end
end
end
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 27cdf8cb7e..029156189d 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -156,17 +156,17 @@ module ActiveRecord
if body.respond_to?(:to_proc)
singleton_class.send(:define_method, name) do |*args|
- scope = all.scoping { instance_exec(*args, &body) }
+ scope = all
+ scope = scope.scoping { instance_exec(*args, &body) || scope }
scope = scope.extending(extension) if extension
-
- scope || all
+ scope
end
else
singleton_class.send(:define_method, name) do |*args|
- scope = all.scoping { body.call(*args) }
+ scope = all
+ scope = scope.scoping { body.call(*args) || scope }
scope = scope.extending(extension) if extension
-
- scope || all
+ scope
end
end
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index c53dee43d7..ba686fc562 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -71,9 +71,9 @@ module ActiveRecord
@tasks[pattern] = task
end
- register_task(/mysql/, 'ActiveRecord::Tasks::MySQLDatabaseTasks')
- register_task(/postgresql/, 'ActiveRecord::Tasks::PostgreSQLDatabaseTasks')
- register_task(/sqlite/, 'ActiveRecord::Tasks::SQLiteDatabaseTasks')
+ register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
+ register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
+ register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
def db_dir
@db_dir ||= Rails.application.config.paths["db"].first