activerecord 6.0.4 → 6.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +767 -846
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -14
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +39 -27
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods.rb +52 -48
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +4 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +215 -49
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +33 -23
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +32 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/model_schema.rb +88 -42
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +59 -44
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +319 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +36 -52
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +5 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +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
@@ -162,13 +162,7 @@ module ActiveRecord
|
|
162
162
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
163
163
|
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
164
164
|
def class_name
|
165
|
-
@class_name ||= (options[:class_name] || derive_class_name)
|
166
|
-
end
|
167
|
-
|
168
|
-
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
169
|
-
|
170
|
-
def join_keys
|
171
|
-
@join_keys ||= get_join_keys(klass)
|
165
|
+
@class_name ||= -(options[:class_name]&.to_s || derive_class_name)
|
172
166
|
end
|
173
167
|
|
174
168
|
# Returns a list of scopes that should be applied for this Reflection
|
@@ -188,10 +182,10 @@ module ActiveRecord
|
|
188
182
|
|
189
183
|
scope_chain_items.inject(klass_scope, &:merge!)
|
190
184
|
|
191
|
-
|
192
|
-
foreign_key =
|
185
|
+
primary_key = join_primary_key
|
186
|
+
foreign_key = join_foreign_key
|
193
187
|
|
194
|
-
klass_scope.where!(table[
|
188
|
+
klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
|
195
189
|
|
196
190
|
if klass.finder_needs_type_condition?
|
197
191
|
klass_scope.where!(klass.send(:type_condition, table))
|
@@ -218,14 +212,14 @@ module ActiveRecord
|
|
218
212
|
end
|
219
213
|
|
220
214
|
def counter_cache_column
|
221
|
-
if belongs_to?
|
215
|
+
@counter_cache_column ||= if belongs_to?
|
222
216
|
if options[:counter_cache] == true
|
223
|
-
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
217
|
+
-"#{active_record.name.demodulize.underscore.pluralize}_count"
|
224
218
|
elsif options[:counter_cache]
|
225
|
-
options[:counter_cache].to_s
|
219
|
+
-options[:counter_cache].to_s
|
226
220
|
end
|
227
221
|
else
|
228
|
-
options[:counter_cache]
|
222
|
+
-(options[:counter_cache]&.to_s || "#{name}_count")
|
229
223
|
end
|
230
224
|
end
|
231
225
|
|
@@ -272,7 +266,7 @@ module ActiveRecord
|
|
272
266
|
def has_cached_counter?
|
273
267
|
options[:counter_cache] ||
|
274
268
|
inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
|
275
|
-
|
269
|
+
active_record.has_attribute?(counter_cache_column)
|
276
270
|
end
|
277
271
|
|
278
272
|
def counter_must_be_updated_by_has_many?
|
@@ -287,10 +281,6 @@ module ActiveRecord
|
|
287
281
|
collect_join_chain
|
288
282
|
end
|
289
283
|
|
290
|
-
def get_join_keys(association_klass)
|
291
|
-
JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
|
292
|
-
end
|
293
|
-
|
294
284
|
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
|
295
285
|
Relation.create(
|
296
286
|
klass,
|
@@ -299,12 +289,8 @@ module ActiveRecord
|
|
299
289
|
)
|
300
290
|
end
|
301
291
|
|
302
|
-
def
|
303
|
-
|
304
|
-
end
|
305
|
-
|
306
|
-
def join_foreign_key
|
307
|
-
active_record_primary_key
|
292
|
+
def strict_loading?
|
293
|
+
options[:strict_loading]
|
308
294
|
end
|
309
295
|
|
310
296
|
protected
|
@@ -428,8 +414,8 @@ module ActiveRecord
|
|
428
414
|
|
429
415
|
def initialize(name, scope, options, active_record)
|
430
416
|
super
|
431
|
-
@type
|
432
|
-
@foreign_type =
|
417
|
+
@type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
|
418
|
+
@foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
|
433
419
|
@constructable = calculate_constructable(macro, options)
|
434
420
|
|
435
421
|
if options[:class_name] && options[:class_name].class == Class
|
@@ -450,24 +436,31 @@ module ActiveRecord
|
|
450
436
|
end
|
451
437
|
|
452
438
|
def join_table
|
453
|
-
@join_table ||= options[:join_table] || derive_join_table
|
439
|
+
@join_table ||= -(options[:join_table]&.to_s || derive_join_table)
|
454
440
|
end
|
455
441
|
|
456
442
|
def foreign_key
|
457
|
-
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
443
|
+
@foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
|
458
444
|
end
|
459
445
|
|
460
446
|
def association_foreign_key
|
461
|
-
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
|
447
|
+
@association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
|
462
448
|
end
|
463
449
|
|
464
|
-
# klass option is necessary to support loading polymorphic associations
|
465
450
|
def association_primary_key(klass = nil)
|
466
|
-
|
451
|
+
primary_key(klass || self.klass)
|
467
452
|
end
|
468
453
|
|
469
454
|
def active_record_primary_key
|
470
|
-
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
455
|
+
@active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
|
456
|
+
end
|
457
|
+
|
458
|
+
def join_primary_key(klass = nil)
|
459
|
+
foreign_key
|
460
|
+
end
|
461
|
+
|
462
|
+
def join_foreign_key
|
463
|
+
active_record_primary_key
|
471
464
|
end
|
472
465
|
|
473
466
|
def check_validity!
|
@@ -683,10 +676,6 @@ module ActiveRecord
|
|
683
676
|
Associations::HasManyAssociation
|
684
677
|
end
|
685
678
|
end
|
686
|
-
|
687
|
-
def association_primary_key(klass = nil)
|
688
|
-
primary_key(klass || self.klass)
|
689
|
-
end
|
690
679
|
end
|
691
680
|
|
692
681
|
class HasOneReflection < AssociationReflection # :nodoc:
|
@@ -721,6 +710,15 @@ module ActiveRecord
|
|
721
710
|
end
|
722
711
|
end
|
723
712
|
|
713
|
+
# klass option is necessary to support loading polymorphic associations
|
714
|
+
def association_primary_key(klass = nil)
|
715
|
+
if primary_key = options[:primary_key]
|
716
|
+
@association_primary_key ||= -primary_key.to_s
|
717
|
+
else
|
718
|
+
primary_key(klass || self.klass)
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
724
722
|
def join_primary_key(klass = nil)
|
725
723
|
polymorphic? ? association_primary_key(klass) : association_primary_key
|
726
724
|
end
|
@@ -729,6 +727,10 @@ module ActiveRecord
|
|
729
727
|
foreign_key
|
730
728
|
end
|
731
729
|
|
730
|
+
def join_foreign_type
|
731
|
+
foreign_type
|
732
|
+
end
|
733
|
+
|
732
734
|
private
|
733
735
|
def can_find_inverse_of_automatically?(_)
|
734
736
|
!polymorphic? && super
|
@@ -750,8 +752,8 @@ module ActiveRecord
|
|
750
752
|
# Holds all the metadata about a :through association as it was specified
|
751
753
|
# in the Active Record class.
|
752
754
|
class ThroughReflection < AbstractReflection #:nodoc:
|
753
|
-
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
|
754
|
-
:active_record_primary_key, :
|
755
|
+
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
|
756
|
+
:active_record_primary_key, :join_foreign_key, to: :source_reflection
|
755
757
|
|
756
758
|
def initialize(delegate_reflection)
|
757
759
|
@delegate_reflection = delegate_reflection
|
@@ -858,7 +860,15 @@ module ActiveRecord
|
|
858
860
|
def association_primary_key(klass = nil)
|
859
861
|
# Get the "actual" source reflection if the immediate source reflection has a
|
860
862
|
# source reflection itself
|
861
|
-
actual_source_reflection.options[:primary_key]
|
863
|
+
if primary_key = actual_source_reflection.options[:primary_key]
|
864
|
+
@association_primary_key ||= -primary_key.to_s
|
865
|
+
else
|
866
|
+
primary_key(klass || self.klass)
|
867
|
+
end
|
868
|
+
end
|
869
|
+
|
870
|
+
def join_primary_key(klass = self.klass)
|
871
|
+
source_reflection.join_primary_key(klass)
|
862
872
|
end
|
863
873
|
|
864
874
|
# Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
|
@@ -907,7 +917,7 @@ module ActiveRecord
|
|
907
917
|
|
908
918
|
def check_validity!
|
909
919
|
if through_reflection.nil?
|
910
|
-
raise HasManyThroughAssociationNotFoundError.new(active_record
|
920
|
+
raise HasManyThroughAssociationNotFoundError.new(active_record, self)
|
911
921
|
end
|
912
922
|
|
913
923
|
if through_reflection.polymorphic?
|
@@ -994,7 +1004,8 @@ module ActiveRecord
|
|
994
1004
|
end
|
995
1005
|
|
996
1006
|
class PolymorphicReflection < AbstractReflection # :nodoc:
|
997
|
-
delegate :klass, :scope, :plural_name, :type, :
|
1007
|
+
delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
|
1008
|
+
:name, :scope_for, to: :@reflection
|
998
1009
|
|
999
1010
|
def initialize(reflection, previous_reflection)
|
1000
1011
|
@reflection = reflection
|
@@ -1019,7 +1030,7 @@ module ActiveRecord
|
|
1019
1030
|
end
|
1020
1031
|
|
1021
1032
|
class RuntimeReflection < AbstractReflection # :nodoc:
|
1022
|
-
delegate :scope, :type, :constraints, :
|
1033
|
+
delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
|
1023
1034
|
|
1024
1035
|
def initialize(reflection, association)
|
1025
1036
|
@reflection = reflection
|
@@ -1031,7 +1042,11 @@ module ActiveRecord
|
|
1031
1042
|
end
|
1032
1043
|
|
1033
1044
|
def aliased_table
|
1034
|
-
|
1045
|
+
klass.arel_table
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def join_primary_key(klass = self.klass)
|
1049
|
+
@reflection.join_primary_key(klass)
|
1035
1050
|
end
|
1036
1051
|
|
1037
1052
|
def all_includes; yield; end
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
:order, :joins, :left_outer_joins, :references,
|
8
8
|
:extending, :unscope, :optimizer_hints, :annotate]
|
9
9
|
|
10
|
-
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
10
|
+
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
|
11
11
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
12
|
|
13
13
|
CLAUSE_METHODS = [:where, :having, :from]
|
@@ -28,7 +28,6 @@ module ActiveRecord
|
|
28
28
|
@klass = klass
|
29
29
|
@table = table
|
30
30
|
@values = values
|
31
|
-
@offsets = {}
|
32
31
|
@loaded = false
|
33
32
|
@predicate_builder = predicate_builder
|
34
33
|
@delegate_to_klass = false
|
@@ -40,8 +39,9 @@ module ActiveRecord
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def arel_attribute(name) # :nodoc:
|
43
|
-
|
42
|
+
table[name]
|
44
43
|
end
|
44
|
+
deprecate :arel_attribute
|
45
45
|
|
46
46
|
def bind_attribute(name, value) # :nodoc:
|
47
47
|
if reflection = klass._reflect_on_association(name)
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
|
50
50
|
end
|
51
51
|
|
52
|
-
attr =
|
52
|
+
attr = table[name]
|
53
53
|
bind = predicate_builder.build_bind_attribute(attr.name, value)
|
54
54
|
yield attr, bind
|
55
55
|
end
|
@@ -67,10 +67,9 @@ module ActiveRecord
|
|
67
67
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
68
|
# user.name # => Oscar
|
69
69
|
def new(attributes = nil, &block)
|
70
|
-
block =
|
71
|
-
scoping {
|
70
|
+
block = current_scope_restoring_block(&block)
|
71
|
+
scoping { _new(attributes, &block) }
|
72
72
|
end
|
73
|
-
|
74
73
|
alias build new
|
75
74
|
|
76
75
|
# Tries to create a new record with the same scoped attributes
|
@@ -96,8 +95,8 @@ module ActiveRecord
|
|
96
95
|
if attributes.is_a?(Array)
|
97
96
|
attributes.collect { |attr| create(attr, &block) }
|
98
97
|
else
|
99
|
-
block =
|
100
|
-
scoping {
|
98
|
+
block = current_scope_restoring_block(&block)
|
99
|
+
scoping { _create(attributes, &block) }
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
@@ -111,8 +110,8 @@ module ActiveRecord
|
|
111
110
|
if attributes.is_a?(Array)
|
112
111
|
attributes.collect { |attr| create!(attr, &block) }
|
113
112
|
else
|
114
|
-
block =
|
115
|
-
scoping {
|
113
|
+
block = current_scope_restoring_block(&block)
|
114
|
+
scoping { _create!(attributes, &block) }
|
116
115
|
end
|
117
116
|
end
|
118
117
|
|
@@ -308,7 +307,7 @@ module ActiveRecord
|
|
308
307
|
# last updated record.
|
309
308
|
#
|
310
309
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
311
|
-
def cache_key(timestamp_column =
|
310
|
+
def cache_key(timestamp_column = "updated_at")
|
312
311
|
@cache_keys ||= {}
|
313
312
|
@cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
|
314
313
|
end
|
@@ -317,7 +316,7 @@ module ActiveRecord
|
|
317
316
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
318
317
|
key = "#{klass.model_name.cache_key}/query-#{query_signature}"
|
319
318
|
|
320
|
-
if
|
319
|
+
if collection_cache_versioning
|
321
320
|
key
|
322
321
|
else
|
323
322
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
@@ -343,15 +342,17 @@ module ActiveRecord
|
|
343
342
|
end
|
344
343
|
|
345
344
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
|
+
timestamp_column = timestamp_column.to_s
|
346
|
+
|
346
347
|
if loaded? || distinct_value
|
347
348
|
size = records.size
|
348
349
|
if size > 0
|
349
|
-
timestamp =
|
350
|
+
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
350
351
|
end
|
351
352
|
else
|
352
353
|
collection = eager_loading? ? apply_join_dependency : self
|
353
354
|
|
354
|
-
column = connection.visitor.compile(
|
355
|
+
column = connection.visitor.compile(table[timestamp_column])
|
355
356
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
356
357
|
|
357
358
|
if collection.has_limit_or_offset?
|
@@ -365,14 +366,12 @@ module ActiveRecord
|
|
365
366
|
arel = query.arel
|
366
367
|
end
|
367
368
|
|
368
|
-
|
369
|
+
size, timestamp = connection.select_rows(arel, nil).first
|
369
370
|
|
370
|
-
if
|
371
|
+
if size
|
371
372
|
column_type = klass.type_for_attribute(timestamp_column)
|
372
|
-
timestamp = column_type.deserialize(
|
373
|
-
size = result["size"]
|
373
|
+
timestamp = column_type.deserialize(timestamp)
|
374
374
|
else
|
375
|
-
timestamp = nil
|
376
375
|
size = 0
|
377
376
|
end
|
378
377
|
end
|
@@ -407,9 +406,9 @@ module ActiveRecord
|
|
407
406
|
already_in_scope? ? yield : _scoping(self) { yield }
|
408
407
|
end
|
409
408
|
|
410
|
-
def _exec_scope(
|
409
|
+
def _exec_scope(*args, &block) # :nodoc:
|
411
410
|
@delegate_to_klass = true
|
412
|
-
_scoping(
|
411
|
+
_scoping(nil) { instance_exec(*args, &block) || self }
|
413
412
|
ensure
|
414
413
|
@delegate_to_klass = false
|
415
414
|
end
|
@@ -417,7 +416,7 @@ module ActiveRecord
|
|
417
416
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
418
417
|
# statement and sends it straight to the database. It does not instantiate the involved models and it does not
|
419
418
|
# trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
|
420
|
-
# Active Record's normal type casting and serialization.
|
419
|
+
# Active Record's normal type casting and serialization. Returns the number of rows affected.
|
421
420
|
#
|
422
421
|
# Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
|
423
422
|
#
|
@@ -448,7 +447,7 @@ module ActiveRecord
|
|
448
447
|
|
449
448
|
stmt = Arel::UpdateManager.new
|
450
449
|
stmt.table(arel.join_sources.empty? ? table : arel.source)
|
451
|
-
stmt.key =
|
450
|
+
stmt.key = table[primary_key]
|
452
451
|
stmt.take(arel.limit)
|
453
452
|
stmt.offset(arel.offset)
|
454
453
|
stmt.order(*arel.orders)
|
@@ -458,7 +457,7 @@ module ActiveRecord
|
|
458
457
|
if klass.locking_enabled? &&
|
459
458
|
!updates.key?(klass.locking_column) &&
|
460
459
|
!updates.key?(klass.locking_column.to_sym)
|
461
|
-
attr =
|
460
|
+
attr = table[klass.locking_column]
|
462
461
|
updates[attr.name] = _increment_attribute(attr)
|
463
462
|
end
|
464
463
|
stmt.set _substitute_values(updates)
|
@@ -477,12 +476,24 @@ module ActiveRecord
|
|
477
476
|
end
|
478
477
|
end
|
479
478
|
|
480
|
-
|
479
|
+
# Updates the counters of the records in the current relation.
|
480
|
+
#
|
481
|
+
# ==== Parameters
|
482
|
+
#
|
483
|
+
# * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
|
484
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
485
|
+
# * If attributes names are passed, they are updated along with update_at/on attributes.
|
486
|
+
#
|
487
|
+
# ==== Examples
|
488
|
+
#
|
489
|
+
# # For Posts by a given author increment the comment_count by 1.
|
490
|
+
# Post.where(author_id: author.id).update_counters(comment_count: 1)
|
491
|
+
def update_counters(counters)
|
481
492
|
touch = counters.delete(:touch)
|
482
493
|
|
483
494
|
updates = {}
|
484
495
|
counters.each do |counter_name, value|
|
485
|
-
attr =
|
496
|
+
attr = table[counter_name]
|
486
497
|
updates[attr.name] = _increment_attribute(attr, value)
|
487
498
|
end
|
488
499
|
|
@@ -578,7 +589,7 @@ module ActiveRecord
|
|
578
589
|
|
579
590
|
stmt = Arel::DeleteManager.new
|
580
591
|
stmt.from(arel.join_sources.empty? ? table : arel.source)
|
581
|
-
stmt.key =
|
592
|
+
stmt.key = table[primary_key]
|
582
593
|
stmt.take(arel.limit)
|
583
594
|
stmt.offset(arel.offset)
|
584
595
|
stmt.order(*arel.orders)
|
@@ -623,7 +634,10 @@ module ActiveRecord
|
|
623
634
|
#
|
624
635
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
625
636
|
def load(&block)
|
626
|
-
|
637
|
+
unless loaded?
|
638
|
+
@records = exec_queries(&block)
|
639
|
+
@loaded = true
|
640
|
+
end
|
627
641
|
|
628
642
|
self
|
629
643
|
end
|
@@ -636,11 +650,9 @@ module ActiveRecord
|
|
636
650
|
|
637
651
|
def reset
|
638
652
|
@delegate_to_klass = false
|
639
|
-
@_deprecated_scope_source = nil
|
640
653
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
654
|
+
@offsets = @take = nil
|
641
655
|
@records = [].freeze
|
642
|
-
@offsets = {}
|
643
|
-
@take = nil
|
644
656
|
self
|
645
657
|
end
|
646
658
|
|
@@ -718,7 +730,7 @@ module ActiveRecord
|
|
718
730
|
end
|
719
731
|
|
720
732
|
def inspect
|
721
|
-
subject = loaded? ? records :
|
733
|
+
subject = loaded? ? records : annotate("loading for inspect")
|
722
734
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
723
735
|
|
724
736
|
entries[10] = "..." if entries.size == 11
|
@@ -735,25 +747,31 @@ module ActiveRecord
|
|
735
747
|
end
|
736
748
|
|
737
749
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
738
|
-
|
739
|
-
|
750
|
+
ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
|
751
|
+
end
|
752
|
+
|
753
|
+
class StrictLoadingScope # :nodoc:
|
754
|
+
def self.empty_scope?
|
755
|
+
true
|
756
|
+
end
|
757
|
+
|
758
|
+
def self.strict_loading_value
|
759
|
+
true
|
760
|
+
end
|
740
761
|
end
|
741
762
|
|
742
763
|
def preload_associations(records) # :nodoc:
|
743
764
|
preload = preload_values
|
744
765
|
preload += includes_values unless eager_loading?
|
745
766
|
preloader = nil
|
767
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
746
768
|
preload.each do |associations|
|
747
769
|
preloader ||= build_preloader
|
748
|
-
preloader.preload records, associations
|
770
|
+
preloader.preload records, associations, scope
|
749
771
|
end
|
750
772
|
end
|
751
773
|
|
752
|
-
attr_reader :_deprecated_scope_source # :nodoc:
|
753
|
-
|
754
774
|
protected
|
755
|
-
attr_writer :_deprecated_scope_source # :nodoc:
|
756
|
-
|
757
775
|
def load_records(records)
|
758
776
|
@records = records.freeze
|
759
777
|
@loaded = true
|
@@ -765,23 +783,29 @@ module ActiveRecord
|
|
765
783
|
|
766
784
|
private
|
767
785
|
def already_in_scope?
|
768
|
-
@delegate_to_klass &&
|
769
|
-
scope = klass.current_scope(true)
|
770
|
-
scope && !scope._deprecated_scope_source
|
771
|
-
end
|
772
|
-
end
|
773
|
-
|
774
|
-
def _deprecated_spawn(name)
|
775
|
-
spawn.tap { |scope| scope._deprecated_scope_source = name }
|
786
|
+
@delegate_to_klass && klass.current_scope(true)
|
776
787
|
end
|
777
788
|
|
778
|
-
def
|
789
|
+
def current_scope_restoring_block(&block)
|
790
|
+
current_scope = klass.current_scope(true)
|
779
791
|
-> record do
|
780
|
-
klass.current_scope =
|
792
|
+
klass.current_scope = current_scope
|
781
793
|
yield record if block_given?
|
782
794
|
end
|
783
795
|
end
|
784
796
|
|
797
|
+
def _new(attributes, &block)
|
798
|
+
klass.new(attributes, &block)
|
799
|
+
end
|
800
|
+
|
801
|
+
def _create(attributes, &block)
|
802
|
+
klass.create(attributes, &block)
|
803
|
+
end
|
804
|
+
|
805
|
+
def _create!(attributes, &block)
|
806
|
+
klass.create!(attributes, &block)
|
807
|
+
end
|
808
|
+
|
785
809
|
def _scoping(scope)
|
786
810
|
previous, klass.current_scope = klass.current_scope(true), scope
|
787
811
|
yield
|
@@ -791,7 +815,7 @@ module ActiveRecord
|
|
791
815
|
|
792
816
|
def _substitute_values(values)
|
793
817
|
values.map do |name, value|
|
794
|
-
attr =
|
818
|
+
attr = table[name]
|
795
819
|
unless Arel.arel_node?(value)
|
796
820
|
type = klass.type_for_attribute(attr.name)
|
797
821
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
@@ -809,27 +833,29 @@ module ActiveRecord
|
|
809
833
|
|
810
834
|
def exec_queries(&block)
|
811
835
|
skip_query_cache_if_necessary do
|
812
|
-
|
813
|
-
if
|
836
|
+
records =
|
837
|
+
if where_clause.contradiction?
|
838
|
+
[]
|
839
|
+
elsif eager_loading?
|
814
840
|
apply_join_dependency do |relation, join_dependency|
|
815
841
|
if relation.null_relation?
|
816
842
|
[]
|
817
843
|
else
|
818
844
|
relation = join_dependency.apply_column_aliases(relation)
|
819
845
|
rows = connection.select_all(relation.arel, "SQL")
|
820
|
-
join_dependency.instantiate(rows, &block)
|
846
|
+
join_dependency.instantiate(rows, strict_loading_value, &block)
|
821
847
|
end.freeze
|
822
848
|
end
|
823
849
|
else
|
824
850
|
klass.find_by_sql(arel, &block).freeze
|
825
851
|
end
|
826
852
|
|
827
|
-
preload_associations(
|
853
|
+
preload_associations(records) unless skip_preloading_value
|
828
854
|
|
829
|
-
|
855
|
+
records.each(&:readonly!) if readonly_value
|
856
|
+
records.each(&:strict_loading!) if strict_loading_value
|
830
857
|
|
831
|
-
|
832
|
-
@records
|
858
|
+
records
|
833
859
|
end
|
834
860
|
end
|
835
861
|
|
@@ -848,27 +874,27 @@ module ActiveRecord
|
|
848
874
|
end
|
849
875
|
|
850
876
|
def references_eager_loaded_tables?
|
851
|
-
joined_tables =
|
877
|
+
joined_tables = build_joins([]).flat_map do |join|
|
852
878
|
if join.is_a?(Arel::Nodes::StringJoin)
|
853
879
|
tables_in_string(join.left)
|
854
880
|
else
|
855
|
-
|
881
|
+
join.left.name
|
856
882
|
end
|
857
883
|
end
|
858
884
|
|
859
|
-
joined_tables
|
885
|
+
joined_tables << table.name
|
860
886
|
|
861
887
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
862
|
-
joined_tables
|
888
|
+
joined_tables.map!(&:downcase)
|
863
889
|
|
864
|
-
(references_values - joined_tables).
|
890
|
+
!(references_values.map(&:to_s) - joined_tables).empty?
|
865
891
|
end
|
866
892
|
|
867
893
|
def tables_in_string(string)
|
868
894
|
return [] if string.blank?
|
869
895
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
870
896
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
871
|
-
string.scan(/
|
897
|
+
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
872
898
|
end
|
873
899
|
end
|
874
900
|
end
|