activerecord 6.0.6.1 → 6.1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1152 -779
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record/aggregations.rb +5 -5
- data/lib/active_record/association_relation.rb +30 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +49 -26
- data/lib/active_record/associations/association_scope.rb +18 -20
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +32 -18
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +14 -8
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +118 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -8
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +218 -71
- data/lib/active_record/core.rb +264 -63
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +69 -34
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +58 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +38 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +24 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +72 -18
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +89 -14
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +279 -101
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +104 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +61 -38
- data/lib/active_record/relation/query_methods.rb +322 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -61
- data/lib/active_record/relation.rb +100 -81
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -3
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -51
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +79 -31
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +19 -66
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +25 -26
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -132,7 +132,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
132
132
|
SQLite3[link:classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
|
133
133
|
|
134
134
|
|
135
|
-
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[
|
135
|
+
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://ruby-doc.org/stdlib/libdoc/logger/rdoc/].
|
136
136
|
|
137
137
|
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
138
138
|
ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
|
@@ -140,7 +140,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
140
140
|
|
141
141
|
* Database agnostic schema management with Migrations.
|
142
142
|
|
143
|
-
class AddSystemSettings < ActiveRecord::Migration[
|
143
|
+
class AddSystemSettings < ActiveRecord::Migration[6.0]
|
144
144
|
def up
|
145
145
|
create_table :system_settings do |t|
|
146
146
|
t.string :name
|
@@ -141,7 +141,7 @@ module ActiveRecord
|
|
141
141
|
# converted to an instance of value class if necessary.
|
142
142
|
#
|
143
143
|
# For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be
|
144
|
-
# aggregated using the +NetAddr::CIDR+ value class (
|
144
|
+
# aggregated using the +NetAddr::CIDR+ value class (https://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
|
145
145
|
# The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
|
146
146
|
# New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string
|
147
147
|
# or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
|
@@ -244,8 +244,8 @@ module ActiveRecord
|
|
244
244
|
private
|
245
245
|
def reader_method(name, class_name, mapping, allow_nil, constructor)
|
246
246
|
define_method(name) do
|
247
|
-
if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !
|
248
|
-
attrs = mapping.collect { |key, _|
|
247
|
+
if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !read_attribute(key).nil? })
|
248
|
+
attrs = mapping.collect { |key, _| read_attribute(key) }
|
249
249
|
object = constructor.respond_to?(:call) ?
|
250
250
|
constructor.call(*attrs) :
|
251
251
|
class_name.constantize.send(constructor, *attrs)
|
@@ -271,10 +271,10 @@ module ActiveRecord
|
|
271
271
|
end
|
272
272
|
|
273
273
|
if part.nil? && allow_nil
|
274
|
-
mapping.each { |key, _|
|
274
|
+
mapping.each { |key, _| write_attribute(key, nil) }
|
275
275
|
@aggregation_cache[name] = nil
|
276
276
|
else
|
277
|
-
mapping.each { |key, value|
|
277
|
+
mapping.each { |key, value| write_attribute(key, part.send(value)) }
|
278
278
|
@aggregation_cache[name] = part.freeze
|
279
279
|
end
|
280
280
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
class AssociationRelation < Relation
|
4
|
+
class AssociationRelation < Relation # :nodoc:
|
5
5
|
def initialize(klass, association, **)
|
6
6
|
super(klass)
|
7
7
|
@association = association
|
@@ -15,23 +15,41 @@ module ActiveRecord
|
|
15
15
|
other == records
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
%w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
|
19
|
+
class_eval <<~RUBY
|
20
|
+
def #{method}(attributes, **kwargs)
|
21
|
+
if @association.reflection.through_reflection?
|
22
|
+
raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
scoping { klass.#{method}(attributes, **kwargs) }
|
26
|
+
end
|
27
|
+
RUBY
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
30
|
+
def build(attributes = nil, &block)
|
31
|
+
if attributes.is_a?(Array)
|
32
|
+
attributes.collect { |attr| build(attr, &block) }
|
33
|
+
else
|
34
|
+
block = current_scope_restoring_block(&block)
|
35
|
+
scoping { _new(attributes, &block) }
|
36
|
+
end
|
32
37
|
end
|
38
|
+
alias new build
|
33
39
|
|
34
40
|
private
|
41
|
+
def _new(attributes, &block)
|
42
|
+
@association.build(attributes, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def _create(attributes, &block)
|
46
|
+
@association.create(attributes, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def _create!(attributes, &block)
|
50
|
+
@association.create!(attributes, &block)
|
51
|
+
end
|
52
|
+
|
35
53
|
def exec_queries
|
36
54
|
super do |record|
|
37
55
|
@association.set_inverse_instance_from_queries(record)
|
@@ -6,9 +6,14 @@ module ActiveRecord
|
|
6
6
|
module Associations
|
7
7
|
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
8
8
|
class AliasTracker # :nodoc:
|
9
|
-
def self.create(connection, initial_table, joins)
|
9
|
+
def self.create(connection, initial_table, joins, aliases = nil)
|
10
10
|
if joins.empty?
|
11
|
-
aliases
|
11
|
+
aliases ||= Hash.new(0)
|
12
|
+
elsif aliases
|
13
|
+
default_proc = aliases.default_proc || proc { 0 }
|
14
|
+
aliases.default_proc = proc { |h, k|
|
15
|
+
h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
|
16
|
+
}
|
12
17
|
else
|
13
18
|
aliases = Hash.new { |h, k|
|
14
19
|
h[k] = initial_count_for(connection, k, joins)
|
@@ -32,8 +37,6 @@ module ActiveRecord
|
|
32
37
|
).size
|
33
38
|
elsif join.is_a?(Arel::Nodes::Join)
|
34
39
|
join.left.name == name ? 1 : 0
|
35
|
-
elsif join.is_a?(Hash)
|
36
|
-
join[name]
|
37
40
|
else
|
38
41
|
raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
|
39
42
|
end
|
@@ -48,25 +51,26 @@ module ActiveRecord
|
|
48
51
|
@connection = connection
|
49
52
|
end
|
50
53
|
|
51
|
-
def aliased_table_for(
|
52
|
-
|
54
|
+
def aliased_table_for(arel_table, table_name = nil)
|
55
|
+
table_name ||= arel_table.name
|
56
|
+
|
57
|
+
if aliases[table_name] == 0
|
53
58
|
# If it's zero, we can have our table_name
|
54
59
|
aliases[table_name] = 1
|
55
|
-
|
60
|
+
arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
56
61
|
else
|
57
62
|
# Otherwise, we need to use an alias
|
58
|
-
aliased_name = @connection.table_alias_for(
|
63
|
+
aliased_name = @connection.table_alias_for(yield)
|
59
64
|
|
60
65
|
# Update the count
|
61
|
-
aliases[aliased_name] += 1
|
66
|
+
count = aliases[aliased_name] += 1
|
62
67
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
aliased_name
|
67
|
-
end
|
68
|
-
Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
|
68
|
+
aliased_name = "#{truncate(aliased_name)}_#{count}" if count > 1
|
69
|
+
|
70
|
+
arel_table = arel_table.alias(aliased_name)
|
69
71
|
end
|
72
|
+
|
73
|
+
arel_table
|
70
74
|
end
|
71
75
|
|
72
76
|
attr_reader :aliases
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/array/wrap"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module Associations
|
7
5
|
# = Active Record Associations
|
@@ -56,6 +54,10 @@ module ActiveRecord
|
|
56
54
|
@inversed = false
|
57
55
|
end
|
58
56
|
|
57
|
+
def reset_negative_cache # :nodoc:
|
58
|
+
reset if loaded? && target.nil?
|
59
|
+
end
|
60
|
+
|
59
61
|
# Reloads the \target and returns +self+ on success.
|
60
62
|
# The QueryCache is cleared if +force+ is true.
|
61
63
|
def reload(force = false)
|
@@ -132,7 +134,15 @@ module ActiveRecord
|
|
132
134
|
self.target = record
|
133
135
|
@inversed = !!record
|
134
136
|
end
|
135
|
-
|
137
|
+
|
138
|
+
def inversed_from_queries(record)
|
139
|
+
if inversable?(record)
|
140
|
+
self.target = record
|
141
|
+
@inversed = true
|
142
|
+
else
|
143
|
+
@inversed = false
|
144
|
+
end
|
145
|
+
end
|
136
146
|
|
137
147
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
138
148
|
# polymorphic_type field on the owner.
|
@@ -191,16 +201,20 @@ module ActiveRecord
|
|
191
201
|
set_inverse_instance(record)
|
192
202
|
end
|
193
203
|
|
194
|
-
def create(attributes =
|
204
|
+
def create(attributes = nil, &block)
|
195
205
|
_create_record(attributes, &block)
|
196
206
|
end
|
197
207
|
|
198
|
-
def create!(attributes =
|
208
|
+
def create!(attributes = nil, &block)
|
199
209
|
_create_record(attributes, true, &block)
|
200
210
|
end
|
201
211
|
|
202
212
|
private
|
203
213
|
def find_target
|
214
|
+
if strict_loading? && owner.validation_context.nil?
|
215
|
+
Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
|
216
|
+
end
|
217
|
+
|
204
218
|
scope = self.scope
|
205
219
|
return scope.to_a if skip_statement_cache?(scope)
|
206
220
|
|
@@ -210,7 +224,13 @@ module ActiveRecord
|
|
210
224
|
end
|
211
225
|
|
212
226
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
213
|
-
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
|
227
|
+
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
|
228
|
+
end
|
229
|
+
|
230
|
+
def strict_loading?
|
231
|
+
return reflection.strict_loading? if reflection.options.key?(:strict_loading)
|
232
|
+
|
233
|
+
owner.strict_loading?
|
214
234
|
end
|
215
235
|
|
216
236
|
# The scope for this association.
|
@@ -239,25 +259,6 @@ module ActiveRecord
|
|
239
259
|
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
|
240
260
|
end
|
241
261
|
|
242
|
-
def creation_attributes
|
243
|
-
attributes = {}
|
244
|
-
|
245
|
-
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
246
|
-
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
247
|
-
|
248
|
-
if reflection.type
|
249
|
-
attributes[reflection.type] = owner.class.polymorphic_name
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
attributes
|
254
|
-
end
|
255
|
-
|
256
|
-
# Sets the owner attributes on the given record
|
257
|
-
def set_owner_attributes(record)
|
258
|
-
creation_attributes.each { |key, value| record[key] = value }
|
259
|
-
end
|
260
|
-
|
261
262
|
# Returns true if there is a foreign key present on the owner which
|
262
263
|
# references the target. This is used to determine whether we can load
|
263
264
|
# the target if the owner is currently a new record (and therefore
|
@@ -305,7 +306,7 @@ module ActiveRecord
|
|
305
306
|
|
306
307
|
# Returns true if record contains the foreign_key
|
307
308
|
def foreign_key_for?(record)
|
308
|
-
record.
|
309
|
+
record._has_attribute?(reflection.foreign_key)
|
309
310
|
end
|
310
311
|
|
311
312
|
# This should be implemented to return the values of the relevant key(s) on the owner,
|
@@ -330,6 +331,28 @@ module ActiveRecord
|
|
330
331
|
klass.scope_attributes? ||
|
331
332
|
reflection.source_reflection.active_record.default_scopes.any?
|
332
333
|
end
|
334
|
+
|
335
|
+
def enqueue_destroy_association(options)
|
336
|
+
job_class = owner.class.destroy_association_async_job
|
337
|
+
|
338
|
+
if job_class
|
339
|
+
owner._after_commit_jobs.push([job_class, options])
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def inversable?(record)
|
344
|
+
record &&
|
345
|
+
((!record.persisted? || !owner.persisted?) || matches_foreign_key?(record))
|
346
|
+
end
|
347
|
+
|
348
|
+
def matches_foreign_key?(record)
|
349
|
+
if foreign_key_for?(record)
|
350
|
+
record.read_attribute(reflection.foreign_key) == owner.id ||
|
351
|
+
(foreign_key_for?(owner) && owner.read_attribute(reflection.foreign_key) == record.id)
|
352
|
+
else
|
353
|
+
owner.read_attribute(reflection.foreign_key) == record.id
|
354
|
+
end
|
355
|
+
end
|
333
356
|
end
|
334
357
|
end
|
335
358
|
end
|
@@ -52,17 +52,16 @@ module ActiveRecord
|
|
52
52
|
attr_reader :value_transformation
|
53
53
|
|
54
54
|
def join(table, constraint)
|
55
|
-
|
55
|
+
Arel::Nodes::LeadingJoin.new(table, Arel::Nodes::On.new(constraint))
|
56
56
|
end
|
57
57
|
|
58
58
|
def last_chain_scope(scope, reflection, owner)
|
59
|
-
|
60
|
-
|
61
|
-
foreign_key = join_keys.foreign_key
|
59
|
+
primary_key = reflection.join_primary_key
|
60
|
+
foreign_key = reflection.join_foreign_key
|
62
61
|
|
63
62
|
table = reflection.aliased_table
|
64
63
|
value = transform_value(owner[foreign_key])
|
65
|
-
scope = apply_scope(scope, table,
|
64
|
+
scope = apply_scope(scope, table, primary_key, value)
|
66
65
|
|
67
66
|
if reflection.type
|
68
67
|
polymorphic_type = transform_value(owner.class.polymorphic_name)
|
@@ -77,13 +76,12 @@ module ActiveRecord
|
|
77
76
|
end
|
78
77
|
|
79
78
|
def next_chain_scope(scope, reflection, next_reflection)
|
80
|
-
|
81
|
-
|
82
|
-
foreign_key = join_keys.foreign_key
|
79
|
+
primary_key = reflection.join_primary_key
|
80
|
+
foreign_key = reflection.join_foreign_key
|
83
81
|
|
84
82
|
table = reflection.aliased_table
|
85
83
|
foreign_table = next_reflection.aliased_table
|
86
|
-
constraint = table[
|
84
|
+
constraint = table[primary_key].eq(foreign_table[foreign_key])
|
87
85
|
|
88
86
|
if reflection.type
|
89
87
|
value = transform_value(next_reflection.klass.polymorphic_name)
|
@@ -108,11 +106,9 @@ module ActiveRecord
|
|
108
106
|
name = reflection.name
|
109
107
|
chain = [Reflection::RuntimeReflection.new(reflection, association)]
|
110
108
|
reflection.chain.drop(1).each do |refl|
|
111
|
-
aliased_table = tracker.aliased_table_for(
|
112
|
-
refl.
|
113
|
-
|
114
|
-
refl.klass.type_caster
|
115
|
-
)
|
109
|
+
aliased_table = tracker.aliased_table_for(refl.klass.arel_table) do
|
110
|
+
refl.alias_candidate(name)
|
111
|
+
end
|
116
112
|
chain << ReflectionProxy.new(refl, aliased_table)
|
117
113
|
end
|
118
114
|
chain
|
@@ -135,15 +131,17 @@ module ActiveRecord
|
|
135
131
|
if scope_chain_item == chain_head.scope
|
136
132
|
scope.merge! item.except(:where, :includes, :unscope, :order)
|
137
133
|
elsif !item.references_values.empty?
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
134
|
+
scope.merge! item.only(:joins, :left_outer_joins)
|
135
|
+
|
136
|
+
associations = item.eager_load_values | item.includes_values
|
137
|
+
|
138
|
+
unless associations.empty?
|
139
|
+
scope.joins! item.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
|
140
|
+
end
|
143
141
|
end
|
144
142
|
|
145
143
|
reflection.all_includes do
|
146
|
-
scope.
|
144
|
+
scope.includes_values |= item.includes_values
|
147
145
|
end
|
148
146
|
|
149
147
|
scope.unscope!(*item.unscope_values)
|
@@ -9,10 +9,21 @@ module ActiveRecord
|
|
9
9
|
|
10
10
|
case options[:dependent]
|
11
11
|
when :destroy
|
12
|
-
target.destroy
|
13
|
-
|
12
|
+
raise ActiveRecord::Rollback unless target.destroy
|
13
|
+
when :destroy_async
|
14
|
+
id = owner.public_send(reflection.foreign_key.to_sym)
|
15
|
+
primary_key_column = reflection.active_record_primary_key.to_sym
|
16
|
+
|
17
|
+
enqueue_destroy_association(
|
18
|
+
owner_model_name: owner.class.to_s,
|
19
|
+
owner_id: owner.id,
|
20
|
+
association_class: reflection.klass.to_s,
|
21
|
+
association_ids: [id],
|
22
|
+
association_primary_key_column: primary_key_column,
|
23
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
24
|
+
)
|
14
25
|
else
|
15
|
-
target.
|
26
|
+
target.public_send(options[:dependent])
|
16
27
|
end
|
17
28
|
end
|
18
29
|
|
@@ -44,7 +55,7 @@ module ActiveRecord
|
|
44
55
|
|
45
56
|
def decrement_counters_before_last_save
|
46
57
|
if reflection.polymorphic?
|
47
|
-
model_was = owner.attribute_before_last_save(reflection.foreign_type)
|
58
|
+
model_was = owner.attribute_before_last_save(reflection.foreign_type)&.constantize
|
48
59
|
else
|
49
60
|
model_was = klass
|
50
61
|
end
|
@@ -68,7 +79,7 @@ module ActiveRecord
|
|
68
79
|
@updated = true
|
69
80
|
end
|
70
81
|
|
71
|
-
replace_keys(record)
|
82
|
+
replace_keys(record, force: true)
|
72
83
|
|
73
84
|
self.target = record
|
74
85
|
end
|
@@ -96,8 +107,12 @@ module ActiveRecord
|
|
96
107
|
reflection.counter_cache_column && owner.persisted?
|
97
108
|
end
|
98
109
|
|
99
|
-
def replace_keys(record)
|
100
|
-
|
110
|
+
def replace_keys(record, force: false)
|
111
|
+
target_key = record ? record._read_attribute(primary_key(record.class)) : nil
|
112
|
+
|
113
|
+
if force || owner[reflection.foreign_key] != target_key
|
114
|
+
owner[reflection.foreign_key] = target_key
|
115
|
+
end
|
101
116
|
end
|
102
117
|
|
103
118
|
def primary_key(klass)
|
@@ -108,11 +123,9 @@ module ActiveRecord
|
|
108
123
|
owner._read_attribute(reflection.foreign_key)
|
109
124
|
end
|
110
125
|
|
111
|
-
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
|
112
|
-
# has_one associations.
|
113
126
|
def invertible_for?(record)
|
114
127
|
inverse = inverse_reflection_for(record)
|
115
|
-
inverse && inverse.has_one?
|
128
|
+
inverse && (inverse.has_one? || ActiveRecord::Base.has_many_inversing)
|
116
129
|
end
|
117
130
|
|
118
131
|
def stale_state
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
|
7
7
|
def klass
|
8
8
|
type = owner[reflection.foreign_type]
|
9
|
-
type.presence && type
|
9
|
+
type.presence && owner.class.polymorphic_class_for(type)
|
10
10
|
end
|
11
11
|
|
12
12
|
def target_changed?
|
@@ -14,9 +14,14 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
|
-
def replace_keys(record)
|
17
|
+
def replace_keys(record, force: false)
|
18
18
|
super
|
19
|
-
|
19
|
+
|
20
|
+
target_type = record ? record.class.polymorphic_name : nil
|
21
|
+
|
22
|
+
if force || owner[reflection.foreign_type] != target_type
|
23
|
+
owner[reflection.foreign_type] = target_type
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
def inverse_reflection_for(record)
|
@@ -18,7 +18,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
18
18
|
end
|
19
19
|
self.extensions = []
|
20
20
|
|
21
|
-
VALID_OPTIONS = [
|
21
|
+
VALID_OPTIONS = [
|
22
|
+
:class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading
|
23
|
+
].freeze # :nodoc:
|
22
24
|
|
23
25
|
def self.build(model, name, scope, options, &block)
|
24
26
|
if model.dangerous_attribute_method?(name)
|
@@ -72,8 +74,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
72
74
|
|
73
75
|
def self.define_callbacks(model, reflection)
|
74
76
|
if dependent = reflection.options[:dependent]
|
75
|
-
check_dependent_options(dependent)
|
77
|
+
check_dependent_options(dependent, model)
|
76
78
|
add_destroy_callbacks(model, reflection)
|
79
|
+
add_after_commit_jobs_callback(model, dependent)
|
77
80
|
end
|
78
81
|
|
79
82
|
Association.extensions.each do |extension|
|
@@ -118,7 +121,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
118
121
|
raise NotImplementedError
|
119
122
|
end
|
120
123
|
|
121
|
-
def self.check_dependent_options(dependent)
|
124
|
+
def self.check_dependent_options(dependent, model)
|
125
|
+
if dependent == :destroy_async && !model.destroy_association_async_job
|
126
|
+
err_message = "ActiveJob is required to use destroy_async on associations"
|
127
|
+
raise ActiveRecord::ActiveJobRequiredError, err_message
|
128
|
+
end
|
122
129
|
unless valid_dependent_options.include? dependent
|
123
130
|
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
|
124
131
|
end
|
@@ -126,11 +133,31 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
126
133
|
|
127
134
|
def self.add_destroy_callbacks(model, reflection)
|
128
135
|
name = reflection.name
|
129
|
-
model.before_destroy
|
136
|
+
model.before_destroy(->(o) { o.association(name).handle_dependency })
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.add_after_commit_jobs_callback(model, dependent)
|
140
|
+
if dependent == :destroy_async
|
141
|
+
mixin = model.generated_association_methods
|
142
|
+
|
143
|
+
unless mixin.method_defined?(:_after_commit_jobs)
|
144
|
+
model.after_commit(-> do
|
145
|
+
_after_commit_jobs.each do |job_class, job_arguments|
|
146
|
+
job_class.perform_later(**job_arguments)
|
147
|
+
end
|
148
|
+
end)
|
149
|
+
|
150
|
+
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
151
|
+
def _after_commit_jobs
|
152
|
+
@_after_commit_jobs ||= []
|
153
|
+
end
|
154
|
+
CODE
|
155
|
+
end
|
156
|
+
end
|
130
157
|
end
|
131
158
|
|
132
159
|
private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
|
133
160
|
:define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
|
134
|
-
:valid_dependent_options, :check_dependent_options, :add_destroy_callbacks
|
161
|
+
:valid_dependent_options, :check_dependent_options, :add_destroy_callbacks, :add_after_commit_jobs_callback
|
135
162
|
end
|
136
163
|
end
|
@@ -7,11 +7,14 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:polymorphic, :
|
10
|
+
valid = super + [:polymorphic, :counter_cache, :optional, :default]
|
11
|
+
valid += [:foreign_type] if options[:polymorphic]
|
12
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
13
|
+
valid
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.valid_dependent_options
|
14
|
-
[:destroy, :delete]
|
17
|
+
[:destroy, :delete, :destroy_async]
|
15
18
|
end
|
16
19
|
|
17
20
|
def self.define_callbacks(model, reflection)
|
@@ -55,19 +58,19 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
55
58
|
|
56
59
|
if old_record
|
57
60
|
if touch != true
|
58
|
-
old_record.
|
61
|
+
old_record.public_send(touch_method, touch)
|
59
62
|
else
|
60
|
-
old_record.
|
63
|
+
old_record.public_send(touch_method)
|
61
64
|
end
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
65
|
-
record = o.
|
68
|
+
record = o.public_send name
|
66
69
|
if record && record.persisted?
|
67
70
|
if touch != true
|
68
|
-
record.
|
71
|
+
record.public_send(touch_method, touch)
|
69
72
|
else
|
70
|
-
record.
|
73
|
+
record.public_send(touch_method)
|
71
74
|
end
|
72
75
|
end
|
73
76
|
end
|
@@ -7,8 +7,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
11
|
-
:after_add, :before_remove, :after_remove, :extend]
|
10
|
+
super + [:before_add, :after_add, :before_remove, :after_remove, :extend]
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.define_callbacks(model, reflection)
|
@@ -31,8 +30,10 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
31
30
|
def self.define_callback(model, callback_name, name, options)
|
32
31
|
full_callback_name = "#{callback_name}_for_#{name}"
|
33
32
|
|
34
|
-
|
35
|
-
|
33
|
+
unless model.method_defined?(full_callback_name)
|
34
|
+
model.class_attribute(full_callback_name, instance_accessor: false, instance_predicate: false)
|
35
|
+
end
|
36
|
+
|
36
37
|
callbacks = Array(options[callback_name.to_sym]).map do |callback|
|
37
38
|
case callback
|
38
39
|
when Symbol
|
@@ -75,7 +75,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
75
75
|
def middle_options(join_model)
|
76
76
|
middle_options = {}
|
77
77
|
middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
|
78
|
-
middle_options[:source] = join_model.left_reflection.name
|
79
78
|
if options.key? :foreign_key
|
80
79
|
middle_options[:foreign_key] = options[:foreign_key]
|
81
80
|
end
|
@@ -7,11 +7,15 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
10
|
+
valid = super + [:counter_cache, :join_table, :index_errors, :ensuring_owner_was]
|
11
|
+
valid += [:as, :foreign_type] if options[:as]
|
12
|
+
valid += [:through, :source, :source_type] if options[:through]
|
13
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
14
|
+
valid
|
11
15
|
end
|
12
16
|
|
13
17
|
def self.valid_dependent_options
|
14
|
-
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
|
18
|
+
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception, :destroy_async]
|
15
19
|
end
|
16
20
|
|
17
21
|
private_class_method :macro, :valid_options, :valid_dependent_options
|