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
@@ -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|
|
@@ -75,6 +75,7 @@ module ActiveRecord
|
|
75
75
|
def reset
|
76
76
|
super
|
77
77
|
@target = []
|
78
|
+
@replaced_or_added_targets = Set.new
|
78
79
|
@association_ids = nil
|
79
80
|
end
|
80
81
|
|
@@ -101,11 +102,11 @@ module ActiveRecord
|
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
104
|
-
def build(attributes =
|
105
|
+
def build(attributes = nil, &block)
|
105
106
|
if attributes.is_a?(Array)
|
106
107
|
attributes.collect { |attr| build(attr, &block) }
|
107
108
|
else
|
108
|
-
add_to_target(build_record(attributes, &block))
|
109
|
+
add_to_target(build_record(attributes, &block), replace: true)
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
@@ -228,7 +229,7 @@ module ActiveRecord
|
|
228
229
|
# If the collection has been loaded
|
229
230
|
# it is equivalent to <tt>collection.size.zero?</tt>. If the
|
230
231
|
# collection has not been loaded, it is equivalent to
|
231
|
-
# <tt
|
232
|
+
# <tt>!collection.exists?</tt>. If the collection has not already been
|
232
233
|
# loaded and you are going to fetch the records anyway it is better to
|
233
234
|
# check <tt>collection.length.zero?</tt>.
|
234
235
|
def empty?
|
@@ -278,11 +279,19 @@ module ActiveRecord
|
|
278
279
|
target
|
279
280
|
end
|
280
281
|
|
281
|
-
def add_to_target(record, skip_callbacks
|
282
|
-
|
283
|
-
|
282
|
+
def add_to_target(record, skip_callbacks: false, replace: false, &block)
|
283
|
+
replace_on_target(record, skip_callbacks, replace: replace || association_scope.distinct_value, &block)
|
284
|
+
end
|
285
|
+
|
286
|
+
def target=(record)
|
287
|
+
return super unless ActiveRecord::Base.has_many_inversing
|
288
|
+
|
289
|
+
case record
|
290
|
+
when Array
|
291
|
+
super
|
292
|
+
else
|
293
|
+
replace_on_target(record, true, replace: true, inversing: true)
|
284
294
|
end
|
285
|
-
replace_on_target(record, index, skip_callbacks, &block)
|
286
295
|
end
|
287
296
|
|
288
297
|
def scope
|
@@ -297,6 +306,8 @@ module ActiveRecord
|
|
297
306
|
|
298
307
|
def find_from_target?
|
299
308
|
loaded? ||
|
309
|
+
owner.strict_loading? ||
|
310
|
+
reflection.strict_loading? ||
|
300
311
|
owner.new_record? ||
|
301
312
|
target.any? { |record| record.new_record? || record.changed? }
|
302
313
|
end
|
@@ -329,14 +340,7 @@ module ActiveRecord
|
|
329
340
|
end
|
330
341
|
end
|
331
342
|
|
332
|
-
persisted + memory
|
333
|
-
end
|
334
|
-
|
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
|
343
|
+
persisted + memory.reject(&:persisted?)
|
340
344
|
end
|
341
345
|
|
342
346
|
def _create_record(attributes, raise = false, &block)
|
@@ -419,7 +423,7 @@ module ActiveRecord
|
|
419
423
|
common_records = intersection(new_target, original_target)
|
420
424
|
common_records.each do |record|
|
421
425
|
skip_callbacks = true
|
422
|
-
replace_on_target(record,
|
426
|
+
replace_on_target(record, skip_callbacks, replace: true)
|
423
427
|
end
|
424
428
|
end
|
425
429
|
|
@@ -442,7 +446,11 @@ module ActiveRecord
|
|
442
446
|
records
|
443
447
|
end
|
444
448
|
|
445
|
-
def replace_on_target(record,
|
449
|
+
def replace_on_target(record, skip_callbacks, replace:, inversing: false)
|
450
|
+
if replace && (!record.new_record? || @replaced_or_added_targets.include?(record))
|
451
|
+
index = @target.index(record)
|
452
|
+
end
|
453
|
+
|
446
454
|
catch(:abort) do
|
447
455
|
callback(:before_add, record)
|
448
456
|
end || return unless skip_callbacks
|
@@ -453,6 +461,12 @@ module ActiveRecord
|
|
453
461
|
|
454
462
|
yield(record) if block_given?
|
455
463
|
|
464
|
+
if !index && @replaced_or_added_targets.include?(record)
|
465
|
+
index = @target.index(record)
|
466
|
+
end
|
467
|
+
|
468
|
+
@replaced_or_added_targets << record if inversing || index || record.new_record?
|
469
|
+
|
456
470
|
if index
|
457
471
|
target[index] = record
|
458
472
|
elsif @_was_loaded || !loaded?
|
@@ -101,7 +101,7 @@ module ActiveRecord
|
|
101
101
|
# converting them into an array and iterating through them using
|
102
102
|
# Array#select.
|
103
103
|
#
|
104
|
-
# person.pets.select { |pet| pet.name
|
104
|
+
# person.pets.select { |pet| /oo/.match?(pet.name) }
|
105
105
|
# # => [
|
106
106
|
# # #<Pet id: 2, name: "Spook", person_id: 1>,
|
107
107
|
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
|
@@ -374,7 +374,7 @@ module ActiveRecord
|
|
374
374
|
# person.pets
|
375
375
|
# # => [#<Pet id: 1, name: "Gorby", group: "cats", person_id: 1>]
|
376
376
|
#
|
377
|
-
# other_pets = [Pet.new(name: 'Puff', group: 'celebrities']
|
377
|
+
# other_pets = [Pet.new(name: 'Puff', group: 'celebrities')]
|
378
378
|
#
|
379
379
|
# person.pets.replace(other_pets)
|
380
380
|
#
|
@@ -921,7 +921,7 @@ module ActiveRecord
|
|
921
921
|
!!@association.include?(record)
|
922
922
|
end
|
923
923
|
|
924
|
-
def proxy_association
|
924
|
+
def proxy_association # :nodoc:
|
925
925
|
@association
|
926
926
|
end
|
927
927
|
|
@@ -1087,17 +1087,24 @@ module ActiveRecord
|
|
1087
1087
|
end
|
1088
1088
|
|
1089
1089
|
def reset_scope # :nodoc:
|
1090
|
-
@offsets =
|
1090
|
+
@offsets = @take = nil
|
1091
1091
|
@scope = nil
|
1092
1092
|
self
|
1093
1093
|
end
|
1094
1094
|
|
1095
|
+
def inspect # :nodoc:
|
1096
|
+
load_target if find_from_target?
|
1097
|
+
super
|
1098
|
+
end
|
1099
|
+
|
1095
1100
|
delegate_methods = [
|
1096
1101
|
QueryMethods,
|
1097
1102
|
SpawnMethods,
|
1098
1103
|
].flat_map { |klass|
|
1099
1104
|
klass.public_instance_methods(false)
|
1100
|
-
} - self.public_instance_methods(false) - [:select] + [
|
1105
|
+
} - self.public_instance_methods(false) - [:select] + [
|
1106
|
+
:scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
|
1107
|
+
]
|
1101
1108
|
|
1102
1109
|
delegate(*delegate_methods, to: :scope)
|
1103
1110
|
|
@@ -16,5 +16,18 @@ module ActiveRecord::Associations
|
|
16
16
|
attrs[reflection.type] = nil if reflection.type.present?
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
# Sets the owner attributes on the given record
|
22
|
+
def set_owner_attributes(record)
|
23
|
+
return if options[:through]
|
24
|
+
|
25
|
+
key = owner._read_attribute(reflection.join_foreign_key)
|
26
|
+
record._write_attribute(reflection.join_primary_key, key)
|
27
|
+
|
28
|
+
if reflection.type
|
29
|
+
record._write_attribute(reflection.type, owner.class.polymorphic_name)
|
30
|
+
end
|
31
|
+
end
|
19
32
|
end
|
20
33
|
end
|
@@ -26,6 +26,28 @@ module ActiveRecord
|
|
26
26
|
# No point in executing the counter update since we're going to destroy the parent anyway
|
27
27
|
load_target.each { |t| t.destroyed_by_association = reflection }
|
28
28
|
destroy_all
|
29
|
+
when :destroy_async
|
30
|
+
load_target.each do |t|
|
31
|
+
t.destroyed_by_association = reflection
|
32
|
+
end
|
33
|
+
|
34
|
+
unless target.empty?
|
35
|
+
association_class = target.first.class
|
36
|
+
primary_key_column = association_class.primary_key.to_sym
|
37
|
+
|
38
|
+
ids = target.collect do |assoc|
|
39
|
+
assoc.public_send(primary_key_column)
|
40
|
+
end
|
41
|
+
|
42
|
+
enqueue_destroy_association(
|
43
|
+
owner_model_name: owner.class.to_s,
|
44
|
+
owner_id: owner.id,
|
45
|
+
association_class: reflection.klass.to_s,
|
46
|
+
association_ids: ids,
|
47
|
+
association_primary_key_column: primary_key_column,
|
48
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
49
|
+
)
|
50
|
+
end
|
29
51
|
else
|
30
52
|
delete_all
|
31
53
|
end
|
@@ -52,7 +74,7 @@ module ActiveRecord
|
|
52
74
|
# the loaded flag is set to true as well.
|
53
75
|
def count_records
|
54
76
|
count = if reflection.has_cached_counter?
|
55
|
-
owner.
|
77
|
+
owner.read_attribute(reflection.counter_cache_column).to_i
|
56
78
|
else
|
57
79
|
scope.count(:all)
|
58
80
|
end
|
@@ -75,7 +97,7 @@ module ActiveRecord
|
|
75
97
|
if reflection.counter_must_be_updated_by_has_many?
|
76
98
|
counter = reflection.counter_cache_column
|
77
99
|
owner.increment(counter, difference)
|
78
|
-
owner.send(:
|
100
|
+
owner.send(:"clear_#{counter}_change")
|
79
101
|
end
|
80
102
|
end
|
81
103
|
|
@@ -8,7 +8,7 @@ module ActiveRecord
|
|
8
8
|
|
9
9
|
def initialize(owner, reflection)
|
10
10
|
super
|
11
|
-
@through_records = {}
|
11
|
+
@through_records = {}.compare_by_identity
|
12
12
|
end
|
13
13
|
|
14
14
|
def concat(*records)
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
# However, after insert_record has been called, the cache is cleared in
|
55
55
|
# order to allow multiple instances of the same record in an association.
|
56
56
|
def build_through_record(record)
|
57
|
-
@through_records[record
|
57
|
+
@through_records[record] ||= begin
|
58
58
|
ensure_mutable
|
59
59
|
|
60
60
|
attributes = through_scope_attributes
|
@@ -65,7 +65,10 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
attr_reader :through_scope
|
69
|
+
|
68
70
|
def through_scope_attributes
|
71
|
+
scope = through_scope || self.scope
|
69
72
|
scope.where_values_hash(through_association.reflection.name.to_s).
|
70
73
|
except!(through_association.reflection.foreign_key,
|
71
74
|
through_association.reflection.klass.inheritance_column)
|
@@ -77,12 +80,13 @@ module ActiveRecord
|
|
77
80
|
association.save!
|
78
81
|
end
|
79
82
|
ensure
|
80
|
-
@through_records.delete(record
|
83
|
+
@through_records.delete(record)
|
81
84
|
end
|
82
85
|
|
83
86
|
def build_record(attributes)
|
84
87
|
ensure_not_nested
|
85
88
|
|
89
|
+
@through_scope = scope
|
86
90
|
record = super
|
87
91
|
|
88
92
|
inverse = source_reflection.inverse_of
|
@@ -95,6 +99,8 @@ module ActiveRecord
|
|
95
99
|
end
|
96
100
|
|
97
101
|
record
|
102
|
+
ensure
|
103
|
+
@through_scope = nil
|
98
104
|
end
|
99
105
|
|
100
106
|
def remove_records(existing_records, records, method)
|
@@ -202,7 +208,7 @@ module ActiveRecord
|
|
202
208
|
end
|
203
209
|
end
|
204
210
|
|
205
|
-
@through_records.delete(record
|
211
|
+
@through_records.delete(record)
|
206
212
|
end
|
207
213
|
end
|
208
214
|
|
@@ -32,6 +32,18 @@ module ActiveRecord
|
|
32
32
|
target.destroyed_by_association = reflection
|
33
33
|
target.destroy
|
34
34
|
throw(:abort) unless target.destroyed?
|
35
|
+
when :destroy_async
|
36
|
+
primary_key_column = target.class.primary_key.to_sym
|
37
|
+
id = target.public_send(primary_key_column)
|
38
|
+
|
39
|
+
enqueue_destroy_association(
|
40
|
+
owner_model_name: owner.class.to_s,
|
41
|
+
owner_id: owner.id,
|
42
|
+
association_class: reflection.klass.to_s,
|
43
|
+
association_ids: [id],
|
44
|
+
association_primary_key_column: primary_key_column,
|
45
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
46
|
+
)
|
35
47
|
when :nullify
|
36
48
|
target.update_columns(nullified_owner_attributes) if target.persisted?
|
37
49
|
end
|
@@ -81,7 +93,9 @@ module ActiveRecord
|
|
81
93
|
target.delete
|
82
94
|
when :destroy
|
83
95
|
target.destroyed_by_association = reflection
|
84
|
-
target.
|
96
|
+
if target.persisted?
|
97
|
+
target.destroy
|
98
|
+
end
|
85
99
|
else
|
86
100
|
nullify_owner_attributes(target)
|
87
101
|
remove_inverse_instance(target)
|
@@ -14,7 +14,6 @@ module ActiveRecord
|
|
14
14
|
super(reflection.klass, children)
|
15
15
|
|
16
16
|
@reflection = reflection
|
17
|
-
@tables = nil
|
18
17
|
end
|
19
18
|
|
20
19
|
def match?(other)
|
@@ -24,32 +23,47 @@ module ActiveRecord
|
|
24
23
|
|
25
24
|
def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
26
25
|
joins = []
|
26
|
+
chain = []
|
27
|
+
|
28
|
+
reflection.chain.each do |reflection|
|
29
|
+
table, terminated = yield reflection
|
30
|
+
@table ||= table
|
31
|
+
|
32
|
+
if terminated
|
33
|
+
foreign_table, foreign_klass = table, reflection.klass
|
34
|
+
break
|
35
|
+
end
|
36
|
+
|
37
|
+
chain << [reflection, table]
|
38
|
+
end
|
27
39
|
|
28
40
|
# The chain starts with the target table, but we want to end with it here (makes
|
29
41
|
# more sense in this context), so we reverse
|
30
|
-
|
31
|
-
table = tables[-i]
|
42
|
+
chain.reverse_each do |reflection, table|
|
32
43
|
klass = reflection.klass
|
33
44
|
|
34
|
-
|
45
|
+
scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
46
|
+
|
47
|
+
unless scope.references_values.empty?
|
48
|
+
associations = scope.eager_load_values | scope.includes_values
|
35
49
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
)
|
40
|
-
join_scope.joins!(join_dependency)
|
50
|
+
unless associations.empty?
|
51
|
+
scope.joins! scope.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
|
52
|
+
end
|
41
53
|
end
|
42
54
|
|
43
|
-
arel =
|
55
|
+
arel = scope.arel(alias_tracker.aliases)
|
44
56
|
nodes = arel.constraints.first
|
45
57
|
|
46
|
-
|
47
|
-
|
58
|
+
if nodes.is_a?(Arel::Nodes::And)
|
59
|
+
others = nodes.children.extract! do |node|
|
60
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
61
|
+
end
|
48
62
|
end
|
49
63
|
|
50
|
-
joins <<
|
64
|
+
joins << join_type.new(table, Arel::Nodes::On.new(nodes))
|
51
65
|
|
52
|
-
|
66
|
+
if others && !others.empty?
|
53
67
|
joins.concat arel.join_sources
|
54
68
|
append_constraints(joins.last, others)
|
55
69
|
end
|
@@ -61,24 +75,26 @@ module ActiveRecord
|
|
61
75
|
joins
|
62
76
|
end
|
63
77
|
|
64
|
-
def tables=(tables)
|
65
|
-
@tables = tables
|
66
|
-
@table = tables.first
|
67
|
-
end
|
68
|
-
|
69
78
|
def readonly?
|
70
79
|
return @readonly if defined?(@readonly)
|
71
80
|
|
72
81
|
@readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value
|
73
82
|
end
|
74
83
|
|
84
|
+
def strict_loading?
|
85
|
+
return @strict_loading if defined?(@strict_loading)
|
86
|
+
|
87
|
+
@strict_loading = reflection.scope && reflection.scope_for(base_klass.unscoped).strict_loading_value
|
88
|
+
end
|
89
|
+
|
75
90
|
private
|
76
91
|
def append_constraints(join, constraints)
|
77
92
|
if join.is_a?(Arel::Nodes::StringJoin)
|
78
|
-
join_string =
|
93
|
+
join_string = Arel::Nodes::And.new(constraints.unshift join.left)
|
79
94
|
join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
|
80
95
|
else
|
81
|
-
join.right
|
96
|
+
right = join.right
|
97
|
+
right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
|
82
98
|
end
|
83
99
|
end
|
84
100
|
end
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
# association.
|
18
18
|
attr_reader :base_klass, :children
|
19
19
|
|
20
|
-
delegate :table_name, :column_names, :primary_key, to: :base_klass
|
20
|
+
delegate :table_name, :column_names, :primary_key, :attribute_types, to: :base_klass
|
21
21
|
|
22
22
|
def initialize(base_klass, children)
|
23
23
|
@base_klass = base_klass
|