activerecord 6.0.3.4 → 6.1.0
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 +799 -713
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- 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 +44 -28
- data/lib/active_record/associations/association_scope.rb +17 -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 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -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 +72 -50
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +11 -5
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods.rb +64 -54
- 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/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +57 -40
- 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.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +191 -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 +112 -27
- 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 +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
- 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 +23 -25
- 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 +32 -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 +11 -7
- 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 +13 -54
- 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 +10 -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/range.rb +24 -5
- 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 +31 -6
- 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 +37 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +229 -63
- 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 +40 -16
- 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 +35 -6
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -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 +117 -13
- 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 +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +71 -57
- data/lib/active_record/relation.rb +96 -67
- 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 +101 -44
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +45 -15
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +27 -25
- 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 +4 -5
- 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 +330 -195
- 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 +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 +2 -8
- data/lib/active_record/scoping/named.rb +6 -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 +39 -51
- 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 +37 -16
- 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/time.rb +10 -0
- 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/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 +27 -28
- 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)
|
@@ -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,27 +201,34 @@ 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 owner.strict_loading? && owner.validation_context.nil?
|
215
|
+
Base.strict_loading_violation!(owner: owner.class, association: klass)
|
216
|
+
end
|
217
|
+
|
218
|
+
if reflection.strict_loading? && owner.validation_context.nil?
|
219
|
+
Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
|
220
|
+
end
|
221
|
+
|
204
222
|
scope = self.scope
|
205
223
|
return scope.to_a if skip_statement_cache?(scope)
|
206
224
|
|
207
|
-
|
208
|
-
sc = reflection.association_scope_cache(conn, owner) do |params|
|
225
|
+
sc = reflection.association_scope_cache(klass, owner) do |params|
|
209
226
|
as = AssociationScope.create { params.bind }
|
210
227
|
target_scope.merge!(as.scope(self))
|
211
228
|
end
|
212
229
|
|
213
230
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
214
|
-
sc.execute(binds,
|
231
|
+
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
|
215
232
|
end
|
216
233
|
|
217
234
|
# The scope for this association.
|
@@ -240,25 +257,6 @@ module ActiveRecord
|
|
240
257
|
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
|
241
258
|
end
|
242
259
|
|
243
|
-
def creation_attributes
|
244
|
-
attributes = {}
|
245
|
-
|
246
|
-
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
247
|
-
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
248
|
-
|
249
|
-
if reflection.type
|
250
|
-
attributes[reflection.type] = owner.class.polymorphic_name
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
attributes
|
255
|
-
end
|
256
|
-
|
257
|
-
# Sets the owner attributes on the given record
|
258
|
-
def set_owner_attributes(record)
|
259
|
-
creation_attributes.each { |key, value| record[key] = value }
|
260
|
-
end
|
261
|
-
|
262
260
|
# Returns true if there is a foreign key present on the owner which
|
263
261
|
# references the target. This is used to determine whether we can load
|
264
262
|
# the target if the owner is currently a new record (and therefore
|
@@ -306,7 +304,7 @@ module ActiveRecord
|
|
306
304
|
|
307
305
|
# Returns true if record contains the foreign_key
|
308
306
|
def foreign_key_for?(record)
|
309
|
-
record.
|
307
|
+
record._has_attribute?(reflection.foreign_key)
|
310
308
|
end
|
311
309
|
|
312
310
|
# This should be implemented to return the values of the relevant key(s) on the owner,
|
@@ -331,6 +329,24 @@ module ActiveRecord
|
|
331
329
|
klass.scope_attributes? ||
|
332
330
|
reflection.source_reflection.active_record.default_scopes.any?
|
333
331
|
end
|
332
|
+
|
333
|
+
def enqueue_destroy_association(options)
|
334
|
+
owner.class.destroy_association_async_job&.perform_later(**options)
|
335
|
+
end
|
336
|
+
|
337
|
+
def inversable?(record)
|
338
|
+
record &&
|
339
|
+
((!record.persisted? || !owner.persisted?) || matches_foreign_key?(record))
|
340
|
+
end
|
341
|
+
|
342
|
+
def matches_foreign_key?(record)
|
343
|
+
if foreign_key_for?(record)
|
344
|
+
record.read_attribute(reflection.foreign_key) == owner.id ||
|
345
|
+
(foreign_key_for?(owner) && owner.read_attribute(reflection.foreign_key) == record.id)
|
346
|
+
else
|
347
|
+
owner.read_attribute(reflection.foreign_key) == record.id
|
348
|
+
end
|
349
|
+
end
|
334
350
|
end
|
335
351
|
end
|
336
352
|
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
|
@@ -134,10 +130,16 @@ module ActiveRecord
|
|
134
130
|
|
135
131
|
if scope_chain_item == chain_head.scope
|
136
132
|
scope.merge! item.except(:where, :includes, :unscope, :order)
|
133
|
+
elsif !item.references_values.empty?
|
134
|
+
join_dependency = item.construct_join_dependency(
|
135
|
+
item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
|
136
|
+
)
|
137
|
+
scope.joins!(*item.joins_values, join_dependency)
|
138
|
+
scope.left_outer_joins!(*item.left_outer_joins_values)
|
137
139
|
end
|
138
140
|
|
139
141
|
reflection.all_includes do
|
140
|
-
scope.
|
142
|
+
scope.includes_values |= item.includes_values
|
141
143
|
end
|
142
144
|
|
143
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
|