activerecord 5.1.7 → 5.2.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 +372 -765
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +4 -2
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +16 -27
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +20 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +4 -5
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +43 -35
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -18
- data/lib/active_record/associations/has_one_association.rb +4 -1
- data/lib/active_record/associations/has_one_through_association.rb +8 -7
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
- data/lib/active_record/associations/join_dependency.rb +23 -43
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +25 -10
- data/lib/active_record/associations.rb +31 -54
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +25 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +8 -2
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +6 -5
- data/lib/active_record/autosave_association.rb +8 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -10
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +111 -38
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -32
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +57 -2
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -78
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +111 -183
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -2
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +246 -110
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +58 -82
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +18 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +80 -90
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +39 -60
- data/lib/active_record/counter_cache.rb +15 -12
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -13
- data/lib/active_record/errors.rb +54 -21
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +14 -17
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +40 -2
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +16 -21
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +166 -16
- data/lib/active_record/query_cache.rb +11 -6
- data/lib/active_record/querying.rb +3 -1
- data/lib/active_record/railtie.rb +61 -3
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +110 -192
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +30 -8
- data/lib/active_record/relation/delegation.rb +15 -27
- data/lib/active_record/relation/finder_methods.rb +75 -78
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +51 -20
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +53 -78
- data/lib/active_record/relation/query_attribute.rb +26 -2
- data/lib/active_record/relation/query_methods.rb +89 -88
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +95 -208
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +21 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +26 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +5 -12
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +9 -7
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +2 -4
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +24 -36
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set/builder.rb +0 -126
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
# = Active Record Association Collection
|
@@ -50,17 +52,19 @@ module ActiveRecord
|
|
50
52
|
|
51
53
|
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
|
52
54
|
def ids_writer(ids)
|
53
|
-
|
55
|
+
primary_key = reflection.association_primary_key
|
56
|
+
pk_type = klass.type_for_attribute(primary_key)
|
54
57
|
ids = Array(ids).reject(&:blank?)
|
55
58
|
ids.map! { |i| pk_type.cast(i) }
|
56
59
|
|
57
|
-
primary_key = reflection.association_primary_key
|
58
60
|
records = klass.where(primary_key => ids).index_by do |r|
|
59
61
|
r.public_send(primary_key)
|
60
62
|
end.values_at(*ids).compact
|
61
63
|
|
62
64
|
if records.size != ids.size
|
63
|
-
|
65
|
+
found_ids = records.map { |record| record.public_send(primary_key) }
|
66
|
+
not_found_ids = ids - found_ids
|
67
|
+
klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
|
64
68
|
else
|
65
69
|
replace(records)
|
66
70
|
end
|
@@ -69,26 +73,29 @@ module ActiveRecord
|
|
69
73
|
def reset
|
70
74
|
super
|
71
75
|
@target = []
|
76
|
+
@association_ids = nil
|
72
77
|
end
|
73
78
|
|
74
79
|
def find(*args)
|
75
|
-
if
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
80
|
+
if options[:inverse_of] && loaded?
|
81
|
+
args_flatten = args.flatten
|
82
|
+
model = scope.klass
|
83
|
+
|
84
|
+
if args_flatten.blank?
|
85
|
+
error_message = "Couldn't find #{model.name} without an ID"
|
86
|
+
raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
|
87
|
+
end
|
88
|
+
|
89
|
+
result = find_by_scan(*args)
|
90
|
+
|
91
|
+
result_size = Array(result).size
|
92
|
+
if !result || result_size != args_flatten.size
|
93
|
+
scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
|
89
94
|
else
|
90
|
-
|
95
|
+
result
|
91
96
|
end
|
97
|
+
else
|
98
|
+
scope.find(*args)
|
92
99
|
end
|
93
100
|
end
|
94
101
|
|
@@ -180,8 +187,6 @@ module ActiveRecord
|
|
180
187
|
# are actually removed from the database, that depends precisely on
|
181
188
|
# +delete_records+. They are in any case removed from the collection.
|
182
189
|
def delete(*records)
|
183
|
-
return if records.empty?
|
184
|
-
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
185
190
|
delete_or_destroy(records, options[:dependent])
|
186
191
|
end
|
187
192
|
|
@@ -191,8 +196,6 @@ module ActiveRecord
|
|
191
196
|
# Note that this method removes records from the database ignoring the
|
192
197
|
# +:dependent+ option.
|
193
198
|
def destroy(*records)
|
194
|
-
return if records.empty?
|
195
|
-
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
196
199
|
delete_or_destroy(records, :destroy)
|
197
200
|
end
|
198
201
|
|
@@ -300,18 +303,17 @@ module ActiveRecord
|
|
300
303
|
private
|
301
304
|
|
302
305
|
def find_target
|
303
|
-
|
306
|
+
scope = self.scope
|
307
|
+
return scope.to_a if skip_statement_cache?(scope)
|
304
308
|
|
305
309
|
conn = klass.connection
|
306
|
-
sc = reflection.association_scope_cache(conn, owner) do
|
307
|
-
|
308
|
-
|
309
|
-
target_scope.merge as.scope(self, conn)
|
310
|
-
}
|
310
|
+
sc = reflection.association_scope_cache(conn, owner) do |params|
|
311
|
+
as = AssociationScope.create { params.bind }
|
312
|
+
target_scope.merge!(as.scope(self))
|
311
313
|
end
|
312
314
|
|
313
315
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
314
|
-
sc.execute(binds,
|
316
|
+
sc.execute(binds, conn) do |record|
|
315
317
|
set_inverse_instance(record)
|
316
318
|
end
|
317
319
|
end
|
@@ -357,7 +359,10 @@ module ActiveRecord
|
|
357
359
|
transaction do
|
358
360
|
add_to_target(build_record(attributes)) do |record|
|
359
361
|
yield(record) if block_given?
|
360
|
-
insert_record(record, true, raise) {
|
362
|
+
insert_record(record, true, raise) {
|
363
|
+
@_was_loaded = loaded?
|
364
|
+
@association_ids = nil
|
365
|
+
}
|
361
366
|
end
|
362
367
|
end
|
363
368
|
end
|
@@ -372,11 +377,9 @@ module ActiveRecord
|
|
372
377
|
end
|
373
378
|
end
|
374
379
|
|
375
|
-
def create_scope
|
376
|
-
scope.scope_for_create.stringify_keys
|
377
|
-
end
|
378
|
-
|
379
380
|
def delete_or_destroy(records, method)
|
381
|
+
return if records.empty?
|
382
|
+
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
380
383
|
records = records.flatten
|
381
384
|
records.each { |record| raise_on_type_mismatch!(record) }
|
382
385
|
existing_records = records.reject(&:new_record?)
|
@@ -430,7 +433,12 @@ module ActiveRecord
|
|
430
433
|
records.each do |record|
|
431
434
|
raise_on_type_mismatch!(record)
|
432
435
|
add_to_target(record) do
|
433
|
-
|
436
|
+
unless owner.new_record?
|
437
|
+
result &&= insert_record(record, true, raise) {
|
438
|
+
@_was_loaded = loaded?
|
439
|
+
@association_ids = nil
|
440
|
+
}
|
441
|
+
end
|
434
442
|
end
|
435
443
|
end
|
436
444
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
# Association proxies in Active Record are middlemen between the object that
|
@@ -30,7 +32,7 @@ module ActiveRecord
|
|
30
32
|
class CollectionProxy < Relation
|
31
33
|
def initialize(klass, association) #:nodoc:
|
32
34
|
@association = association
|
33
|
-
super klass
|
35
|
+
super klass
|
34
36
|
|
35
37
|
extensions = association.extensions
|
36
38
|
extend(*extensions) if extensions.any?
|
@@ -133,8 +135,9 @@ module ActiveRecord
|
|
133
135
|
# # #<Pet id: 2, name: "Spook", person_id: 1>,
|
134
136
|
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
|
135
137
|
# # ]
|
136
|
-
def find(*args
|
137
|
-
|
138
|
+
def find(*args)
|
139
|
+
return super if block_given?
|
140
|
+
@association.find(*args)
|
138
141
|
end
|
139
142
|
|
140
143
|
##
|
@@ -746,10 +749,6 @@ module ActiveRecord
|
|
746
749
|
# # ]
|
747
750
|
|
748
751
|
#--
|
749
|
-
def uniq
|
750
|
-
load_target.uniq
|
751
|
-
end
|
752
|
-
|
753
752
|
def calculate(operation, column_name)
|
754
753
|
null_scope? ? scope.calculate(operation, column_name) : super
|
755
754
|
end
|
@@ -989,6 +988,12 @@ module ActiveRecord
|
|
989
988
|
load_target == other
|
990
989
|
end
|
991
990
|
|
991
|
+
##
|
992
|
+
# :method: to_ary
|
993
|
+
#
|
994
|
+
# :call-seq:
|
995
|
+
# to_ary()
|
996
|
+
#
|
992
997
|
# Returns a new array of objects from the collection. If the collection
|
993
998
|
# hasn't been loaded, it fetches the records from the database.
|
994
999
|
#
|
@@ -1022,10 +1027,6 @@ module ActiveRecord
|
|
1022
1027
|
# # #<Pet id: 5, name: "Brain", person_id: 1>,
|
1023
1028
|
# # #<Pet id: 6, name: "Boss", person_id: 1>
|
1024
1029
|
# # ]
|
1025
|
-
def to_ary
|
1026
|
-
load_target.dup
|
1027
|
-
end
|
1028
|
-
alias_method :to_a, :to_ary
|
1029
1030
|
|
1030
1031
|
def records # :nodoc:
|
1031
1032
|
load_target
|
@@ -1073,7 +1074,6 @@ module ActiveRecord
|
|
1073
1074
|
end
|
1074
1075
|
|
1075
1076
|
# Reloads the collection from the database. Returns +self+.
|
1076
|
-
# Equivalent to <tt>collection(true)</tt>.
|
1077
1077
|
#
|
1078
1078
|
# class Person < ActiveRecord::Base
|
1079
1079
|
# has_many :pets
|
@@ -1087,9 +1087,6 @@ module ActiveRecord
|
|
1087
1087
|
#
|
1088
1088
|
# person.pets.reload # fetches pets from the database
|
1089
1089
|
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
|
1090
|
-
#
|
1091
|
-
# person.pets(true) # fetches pets from the database
|
1092
|
-
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
|
1093
1090
|
def reload
|
1094
1091
|
proxy_association.reload
|
1095
1092
|
reset_scope
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has Many Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has Many Association
|
4
6
|
# This is the proxy that handles a has many association.
|
5
7
|
#
|
6
8
|
# If the association has a <tt>:through</tt> option further specialization
|
@@ -1,14 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has Many Through Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has Many Through Association
|
4
6
|
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
|
5
7
|
include ThroughAssociation
|
6
8
|
|
7
9
|
def initialize(owner, reflection)
|
8
10
|
super
|
9
|
-
|
10
|
-
@through_records = {}
|
11
|
-
@through_association = nil
|
11
|
+
@through_records = {}
|
12
12
|
end
|
13
13
|
|
14
14
|
def concat(*records)
|
@@ -48,11 +48,6 @@ module ActiveRecord
|
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
51
|
-
|
52
|
-
def through_association
|
53
|
-
@through_association ||= owner.association(through_reflection.name)
|
54
|
-
end
|
55
|
-
|
56
51
|
# The through record (built with build_record) is temporarily cached
|
57
52
|
# so that it may be reused if insert_record is subsequently called.
|
58
53
|
#
|
@@ -138,21 +133,15 @@ module ActiveRecord
|
|
138
133
|
|
139
134
|
scope = through_association.scope
|
140
135
|
scope.where! construct_join_attributes(*records)
|
136
|
+
scope = scope.where(through_scope_attributes)
|
141
137
|
|
142
138
|
case method
|
143
139
|
when :destroy
|
144
140
|
if scope.klass.primary_key
|
145
|
-
count = scope.destroy_all.
|
141
|
+
count = scope.destroy_all.count(&:destroyed?)
|
146
142
|
else
|
147
143
|
scope.each(&:_run_destroy_callbacks)
|
148
|
-
|
149
|
-
arel = scope.arel
|
150
|
-
|
151
|
-
stmt = Arel::DeleteManager.new
|
152
|
-
stmt.from scope.klass.arel_table
|
153
|
-
stmt.wheres = arel.constraints
|
154
|
-
|
155
|
-
count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes)
|
144
|
+
count = scope.delete_all
|
156
145
|
end
|
157
146
|
when :nullify
|
158
147
|
count = scope.update_all(source_reflection.foreign_key => nil)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has One Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has One Association
|
4
6
|
class HasOneAssociation < SingularAssociation #:nodoc:
|
5
7
|
include ForeignAssociation
|
6
8
|
|
@@ -58,6 +60,7 @@ module ActiveRecord
|
|
58
60
|
when :destroy
|
59
61
|
target.destroyed_by_association = reflection
|
60
62
|
target.destroy
|
63
|
+
throw(:abort) unless target.destroyed?
|
61
64
|
when :nullify
|
62
65
|
target.update_columns(reflection.foreign_key => nil) if target.persisted?
|
63
66
|
end
|
@@ -1,20 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has One Through Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has One Through Association
|
4
6
|
class HasOneThroughAssociation < HasOneAssociation #:nodoc:
|
5
7
|
include ThroughAssociation
|
6
8
|
|
7
|
-
def replace(record)
|
8
|
-
create_through_record(record)
|
9
|
+
def replace(record, save = true)
|
10
|
+
create_through_record(record, save)
|
9
11
|
self.target = record
|
10
12
|
end
|
11
13
|
|
12
14
|
private
|
13
|
-
|
14
|
-
def create_through_record(record)
|
15
|
+
def create_through_record(record, save)
|
15
16
|
ensure_not_nested
|
16
17
|
|
17
|
-
through_proxy =
|
18
|
+
through_proxy = through_association
|
18
19
|
through_record = through_proxy.load_target
|
19
20
|
|
20
21
|
if through_record && !record
|
@@ -28,7 +29,7 @@ module ActiveRecord
|
|
28
29
|
|
29
30
|
if through_record
|
30
31
|
through_record.update(attributes)
|
31
|
-
elsif owner.new_record?
|
32
|
+
elsif owner.new_record? || !save
|
32
33
|
through_proxy.build(attributes)
|
33
34
|
else
|
34
35
|
through_proxy.create(attributes)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/associations/join_dependency/join_part"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -9,11 +11,12 @@ module ActiveRecord
|
|
9
11
|
|
10
12
|
attr_accessor :tables
|
11
13
|
|
12
|
-
def initialize(reflection, children)
|
14
|
+
def initialize(reflection, children, alias_tracker)
|
13
15
|
super(reflection.klass, children)
|
14
16
|
|
15
|
-
@
|
16
|
-
@
|
17
|
+
@alias_tracker = alias_tracker
|
18
|
+
@reflection = reflection
|
19
|
+
@tables = nil
|
17
20
|
end
|
18
21
|
|
19
22
|
def match?(other)
|
@@ -21,11 +24,8 @@ module ActiveRecord
|
|
21
24
|
super && reflection == other.reflection
|
22
25
|
end
|
23
26
|
|
24
|
-
JoinInformation = Struct.new :joins, :binds
|
25
|
-
|
26
27
|
def join_constraints(foreign_table, foreign_klass, join_type, tables, chain)
|
27
28
|
joins = []
|
28
|
-
binds = []
|
29
29
|
tables = tables.reverse
|
30
30
|
|
31
31
|
# The chain starts with the target table, but we want to end with it here (makes
|
@@ -34,71 +34,32 @@ module ActiveRecord
|
|
34
34
|
table = tables.shift
|
35
35
|
klass = reflection.klass
|
36
36
|
|
37
|
-
|
38
|
-
key = join_keys.key
|
39
|
-
foreign_key = join_keys.foreign_key
|
40
|
-
|
41
|
-
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
|
42
|
-
|
43
|
-
rel = reflection.join_scope(table)
|
37
|
+
constraint = reflection.build_join_constraint(table, foreign_table)
|
44
38
|
|
45
|
-
|
46
|
-
binds += rel.bound_attributes
|
47
|
-
constraint = constraint.and rel.arel.constraints
|
48
|
-
end
|
39
|
+
joins << table.create_join(table, table.create_on(constraint), join_type)
|
49
40
|
|
50
|
-
|
51
|
-
|
52
|
-
column = klass.columns_hash[reflection.type.to_s]
|
41
|
+
join_scope = reflection.join_scope(table, foreign_klass)
|
42
|
+
arel = join_scope.arel(alias_tracker.aliases)
|
53
43
|
|
54
|
-
|
55
|
-
|
44
|
+
if arel.constraints.any?
|
45
|
+
joins.concat arel.join_sources
|
46
|
+
right = joins.last.right
|
47
|
+
right.expr = right.expr.and(arel.constraints)
|
56
48
|
end
|
57
49
|
|
58
|
-
joins << table.create_join(table, table.create_on(constraint), join_type)
|
59
|
-
|
60
50
|
# The current table in this iteration becomes the foreign table in the next
|
61
51
|
foreign_table, foreign_klass = table, klass
|
62
52
|
end
|
63
53
|
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
# Builds equality condition.
|
68
|
-
#
|
69
|
-
# Example:
|
70
|
-
#
|
71
|
-
# class Physician < ActiveRecord::Base
|
72
|
-
# has_many :appointments
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
# If I execute `Physician.joins(:appointments).to_a` then
|
76
|
-
# klass # => Physician
|
77
|
-
# table # => #<Arel::Table @name="appointments" ...>
|
78
|
-
# key # => physician_id
|
79
|
-
# foreign_table # => #<Arel::Table @name="physicians" ...>
|
80
|
-
# foreign_key # => id
|
81
|
-
#
|
82
|
-
def build_constraint(klass, table, key, foreign_table, foreign_key)
|
83
|
-
constraint = table[key].eq(foreign_table[foreign_key])
|
84
|
-
|
85
|
-
if klass.finder_needs_type_condition?
|
86
|
-
constraint = table.create_and([
|
87
|
-
constraint,
|
88
|
-
klass.send(:type_condition, table)
|
89
|
-
])
|
90
|
-
end
|
91
|
-
|
92
|
-
constraint
|
54
|
+
joins
|
93
55
|
end
|
94
56
|
|
95
57
|
def table
|
96
58
|
tables.first
|
97
59
|
end
|
98
60
|
|
99
|
-
|
100
|
-
|
101
|
-
end
|
61
|
+
protected
|
62
|
+
attr_reader :alias_tracker
|
102
63
|
end
|
103
64
|
end
|
104
65
|
end
|
@@ -1,20 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/associations/join_dependency/join_part"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Associations
|
5
7
|
class JoinDependency # :nodoc:
|
6
8
|
class JoinBase < JoinPart # :nodoc:
|
7
|
-
|
8
|
-
return true if self == other
|
9
|
-
super && base_klass == other.base_klass
|
10
|
-
end
|
9
|
+
attr_reader :table
|
11
10
|
|
12
|
-
def table
|
13
|
-
base_klass
|
11
|
+
def initialize(base_klass, table, children)
|
12
|
+
super(base_klass, children)
|
13
|
+
@table = table
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def match?(other)
|
17
|
+
return true if self == other
|
18
|
+
super && base_klass == other.base_klass
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class JoinDependency # :nodoc:
|
@@ -22,10 +24,6 @@ module ActiveRecord
|
|
22
24
|
@children = children
|
23
25
|
end
|
24
26
|
|
25
|
-
def name
|
26
|
-
reflection.name
|
27
|
-
end
|
28
|
-
|
29
27
|
def match?(other)
|
30
28
|
self.class == other.class
|
31
29
|
end
|
@@ -40,11 +38,6 @@ module ActiveRecord
|
|
40
38
|
raise NotImplementedError
|
41
39
|
end
|
42
40
|
|
43
|
-
# The alias for the active_record's table
|
44
|
-
def aliased_table_name
|
45
|
-
raise NotImplementedError
|
46
|
-
end
|
47
|
-
|
48
41
|
def extract_record(row, column_names_with_alias)
|
49
42
|
# This code is performance critical as it is called per row.
|
50
43
|
# see: https://github.com/rails/rails/pull/12185
|