activerecord 6.0.4.1 → 6.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +767 -851
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -14
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +39 -27
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- 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 +19 -13
- 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.rb +63 -49
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods.rb +52 -48
- 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 +4 -4
- 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/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- 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 +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
- 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 +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- 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 +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- 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 -10
- 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/money.rb +2 -2
- 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/quoting.rb +4 -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 +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -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_handling.rb +210 -71
- data/lib/active_record/core.rb +215 -49
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -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/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +33 -23
- 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 +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +32 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/model_schema.rb +88 -42
- 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/databases.rake +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +59 -44
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +100 -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.rb +57 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +319 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- data/lib/active_record/relation/where_clause.rb +104 -57
- 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 +0 -4
- 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 +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +36 -52
- data/lib/active_record/tasks/database_tasks.rb +139 -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 +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type/serialized.rb +6 -2
- 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.rb +1 -0
- 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/arel.rb +5 -13
- 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.rb +3 -1
- 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 +72 -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/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- 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/rails/generators/active_record/migration.rb +6 -1
- 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/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +30 -31
- 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
@@ -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)
|
@@ -129,8 +131,12 @@ module ActiveRecord
|
|
129
131
|
end
|
130
132
|
|
131
133
|
def inversed_from(record)
|
132
|
-
|
133
|
-
|
134
|
+
if inversable?(record)
|
135
|
+
self.target = record
|
136
|
+
@inversed = true
|
137
|
+
else
|
138
|
+
@inversed = false
|
139
|
+
end
|
134
140
|
end
|
135
141
|
alias :inversed_from_queries :inversed_from
|
136
142
|
|
@@ -191,16 +197,24 @@ module ActiveRecord
|
|
191
197
|
set_inverse_instance(record)
|
192
198
|
end
|
193
199
|
|
194
|
-
def create(attributes =
|
200
|
+
def create(attributes = nil, &block)
|
195
201
|
_create_record(attributes, &block)
|
196
202
|
end
|
197
203
|
|
198
|
-
def create!(attributes =
|
204
|
+
def create!(attributes = nil, &block)
|
199
205
|
_create_record(attributes, true, &block)
|
200
206
|
end
|
201
207
|
|
202
208
|
private
|
203
209
|
def find_target
|
210
|
+
if owner.strict_loading?
|
211
|
+
Base.strict_loading_violation!(owner: owner.class, association: klass)
|
212
|
+
end
|
213
|
+
|
214
|
+
if reflection.strict_loading?
|
215
|
+
Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
|
216
|
+
end
|
217
|
+
|
204
218
|
scope = self.scope
|
205
219
|
return scope.to_a if skip_statement_cache?(scope)
|
206
220
|
|
@@ -210,7 +224,7 @@ 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) }
|
214
228
|
end
|
215
229
|
|
216
230
|
# The scope for this association.
|
@@ -239,25 +253,6 @@ module ActiveRecord
|
|
239
253
|
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
|
240
254
|
end
|
241
255
|
|
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
256
|
# Returns true if there is a foreign key present on the owner which
|
262
257
|
# references the target. This is used to determine whether we can load
|
263
258
|
# the target if the owner is currently a new record (and therefore
|
@@ -305,7 +300,7 @@ module ActiveRecord
|
|
305
300
|
|
306
301
|
# Returns true if record contains the foreign_key
|
307
302
|
def foreign_key_for?(record)
|
308
|
-
record.
|
303
|
+
record._has_attribute?(reflection.foreign_key)
|
309
304
|
end
|
310
305
|
|
311
306
|
# This should be implemented to return the values of the relevant key(s) on the owner,
|
@@ -330,6 +325,23 @@ module ActiveRecord
|
|
330
325
|
klass.scope_attributes? ||
|
331
326
|
reflection.source_reflection.active_record.default_scopes.any?
|
332
327
|
end
|
328
|
+
|
329
|
+
def enqueue_destroy_association(options)
|
330
|
+
owner.class.destroy_association_async_job&.perform_later(**options)
|
331
|
+
end
|
332
|
+
|
333
|
+
def inversable?(record)
|
334
|
+
record &&
|
335
|
+
((!record.persisted? || !owner.persisted?) || matches_foreign_key?(record))
|
336
|
+
end
|
337
|
+
|
338
|
+
def matches_foreign_key?(record)
|
339
|
+
if foreign_key_for?(record)
|
340
|
+
record.read_attribute(reflection.foreign_key) == owner.id
|
341
|
+
else
|
342
|
+
owner.read_attribute(reflection.foreign_key) == record.id
|
343
|
+
end
|
344
|
+
end
|
333
345
|
end
|
334
346
|
end
|
335
347
|
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
|
@@ -143,7 +139,7 @@ module ActiveRecord
|
|
143
139
|
end
|
144
140
|
|
145
141
|
reflection.all_includes do
|
146
|
-
scope.
|
142
|
+
scope.includes_values |= item.includes_values
|
147
143
|
end
|
148
144
|
|
149
145
|
scope.unscope!(*item.unscope_values)
|
@@ -11,8 +11,20 @@ module ActiveRecord
|
|
11
11
|
when :destroy
|
12
12
|
target.destroy
|
13
13
|
raise ActiveRecord::Rollback unless target.destroyed?
|
14
|
+
when :destroy_async
|
15
|
+
id = owner.public_send(reflection.foreign_key.to_sym)
|
16
|
+
primary_key_column = reflection.active_record_primary_key.to_sym
|
17
|
+
|
18
|
+
enqueue_destroy_association(
|
19
|
+
owner_model_name: owner.class.to_s,
|
20
|
+
owner_id: owner.id,
|
21
|
+
association_class: reflection.klass.to_s,
|
22
|
+
association_ids: [id],
|
23
|
+
association_primary_key_column: primary_key_column,
|
24
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
25
|
+
)
|
14
26
|
else
|
15
|
-
target.
|
27
|
+
target.public_send(options[:dependent])
|
16
28
|
end
|
17
29
|
end
|
18
30
|
|
@@ -44,7 +56,7 @@ module ActiveRecord
|
|
44
56
|
|
45
57
|
def decrement_counters_before_last_save
|
46
58
|
if reflection.polymorphic?
|
47
|
-
model_was = owner.attribute_before_last_save(reflection.foreign_type)
|
59
|
+
model_was = owner.attribute_before_last_save(reflection.foreign_type)&.constantize
|
48
60
|
else
|
49
61
|
model_was = klass
|
50
62
|
end
|
@@ -108,11 +120,9 @@ module ActiveRecord
|
|
108
120
|
owner._read_attribute(reflection.foreign_key)
|
109
121
|
end
|
110
122
|
|
111
|
-
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
|
112
|
-
# has_one associations.
|
113
123
|
def invertible_for?(record)
|
114
124
|
inverse = inverse_reflection_for(record)
|
115
|
-
inverse && inverse.has_one?
|
125
|
+
inverse && (inverse.has_one? || ActiveRecord::Base.has_many_inversing)
|
116
126
|
end
|
117
127
|
|
118
128
|
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?
|
@@ -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,7 +74,7 @@ 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)
|
77
79
|
end
|
78
80
|
|
@@ -118,7 +120,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
118
120
|
raise NotImplementedError
|
119
121
|
end
|
120
122
|
|
121
|
-
def self.check_dependent_options(dependent)
|
123
|
+
def self.check_dependent_options(dependent, model)
|
124
|
+
if dependent == :destroy_async && !model.destroy_association_async_job
|
125
|
+
err_message = "ActiveJob is required to use destroy_async on associations"
|
126
|
+
raise ActiveRecord::ActiveJobRequiredError, err_message
|
127
|
+
end
|
122
128
|
unless valid_dependent_options.include? dependent
|
123
129
|
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
|
124
130
|
end
|
@@ -7,11 +7,14 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
10
|
+
valid = super + [:counter_cache, :optional, :default]
|
11
|
+
valid += [:polymorphic, :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
|
@@ -7,13 +7,15 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
valid = super
|
10
|
+
valid = super
|
11
|
+
valid += [:as, :foreign_type] if options[:as]
|
12
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
11
13
|
valid += [:through, :source, :source_type] if options[:through]
|
12
14
|
valid
|
13
15
|
end
|
14
16
|
|
15
17
|
def self.valid_dependent_options
|
16
|
-
[:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
18
|
+
[:destroy, :destroy_async, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
17
19
|
end
|
18
20
|
|
19
21
|
def self.define_callbacks(model, reflection)
|
@@ -32,15 +34,12 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
def self.touch_record(
|
36
|
-
|
37
|
+
def self.touch_record(record, name, touch)
|
38
|
+
instance = record.send(name)
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
record.touch(touch)
|
42
|
-
else
|
43
|
-
record.touch
|
40
|
+
if instance&.persisted?
|
41
|
+
touch != true ?
|
42
|
+
instance.touch(touch) : instance.touch
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -48,11 +47,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
48
47
|
name = reflection.name
|
49
48
|
touch = reflection.options[:touch]
|
50
49
|
|
51
|
-
callback =
|
52
|
-
HasOne.touch_record(record, name, touch)
|
53
|
-
}
|
54
|
-
|
50
|
+
callback = -> (record) { HasOne.touch_record(record, name, touch) }
|
55
51
|
model.after_create callback, if: :saved_changes?
|
52
|
+
model.after_create_commit { association(name).reset_negative_cache }
|
56
53
|
model.after_update callback, if: :saved_changes?
|
57
54
|
model.after_destroy callback
|
58
55
|
model.after_touch callback
|
@@ -5,7 +5,7 @@
|
|
5
5
|
module ActiveRecord::Associations::Builder # :nodoc:
|
6
6
|
class SingularAssociation < Association #:nodoc:
|
7
7
|
def self.valid_options(options)
|
8
|
-
super + [:
|
8
|
+
super + [:required, :touch]
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.define_accessors(model, reflection)
|
@@ -56,7 +56,7 @@ module ActiveRecord
|
|
56
56
|
def ids_writer(ids)
|
57
57
|
primary_key = reflection.association_primary_key
|
58
58
|
pk_type = klass.type_for_attribute(primary_key)
|
59
|
-
ids = Array(ids).
|
59
|
+
ids = Array(ids).compact_blank
|
60
60
|
ids.map! { |i| pk_type.cast(i) }
|
61
61
|
|
62
62
|
records = klass.where(primary_key => ids).index_by do |r|
|
@@ -101,11 +101,11 @@ module ActiveRecord
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
def build(attributes =
|
104
|
+
def build(attributes = nil, &block)
|
105
105
|
if attributes.is_a?(Array)
|
106
106
|
attributes.collect { |attr| build(attr, &block) }
|
107
107
|
else
|
108
|
-
add_to_target(build_record(attributes, &block))
|
108
|
+
add_to_target(build_record(attributes, &block), replace: true)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -228,7 +228,7 @@ module ActiveRecord
|
|
228
228
|
# If the collection has been loaded
|
229
229
|
# it is equivalent to <tt>collection.size.zero?</tt>. If the
|
230
230
|
# collection has not been loaded, it is equivalent to
|
231
|
-
# <tt
|
231
|
+
# <tt>!collection.exists?</tt>. If the collection has not already been
|
232
232
|
# loaded and you are going to fetch the records anyway it is better to
|
233
233
|
# check <tt>collection.length.zero?</tt>.
|
234
234
|
def empty?
|
@@ -278,13 +278,24 @@ module ActiveRecord
|
|
278
278
|
target
|
279
279
|
end
|
280
280
|
|
281
|
-
def add_to_target(record, skip_callbacks
|
282
|
-
if association_scope.distinct_value
|
281
|
+
def add_to_target(record, skip_callbacks: false, replace: false, &block)
|
282
|
+
if replace || association_scope.distinct_value
|
283
283
|
index = @target.index(record)
|
284
284
|
end
|
285
285
|
replace_on_target(record, index, skip_callbacks, &block)
|
286
286
|
end
|
287
287
|
|
288
|
+
def target=(record)
|
289
|
+
return super unless ActiveRecord::Base.has_many_inversing
|
290
|
+
|
291
|
+
case record
|
292
|
+
when Array
|
293
|
+
super
|
294
|
+
else
|
295
|
+
add_to_target(record, skip_callbacks: true, replace: true)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
288
299
|
def scope
|
289
300
|
scope = super
|
290
301
|
scope.none! if null_scope?
|
@@ -297,6 +308,8 @@ module ActiveRecord
|
|
297
308
|
|
298
309
|
def find_from_target?
|
299
310
|
loaded? ||
|
311
|
+
owner.strict_loading? ||
|
312
|
+
reflection.strict_loading? ||
|
300
313
|
owner.new_record? ||
|
301
314
|
target.any? { |record| record.new_record? || record.changed? }
|
302
315
|
end
|
@@ -332,13 +345,6 @@ module ActiveRecord
|
|
332
345
|
persisted + memory
|
333
346
|
end
|
334
347
|
|
335
|
-
def build_record(attributes)
|
336
|
-
previous = klass.current_scope(true) if block_given?
|
337
|
-
super
|
338
|
-
ensure
|
339
|
-
klass.current_scope = previous if previous
|
340
|
-
end
|
341
|
-
|
342
348
|
def _create_record(attributes, raise = false, &block)
|
343
349
|
unless owner.persisted?
|
344
350
|
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|