activerecord 6.0.4.8 → 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 +764 -883
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- 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/join_association.rb +29 -14
- 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 +13 -5
- 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 +114 -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 +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/attribute_methods.rb +52 -48
- 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/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/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/oid.rb +2 -0
- 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_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +215 -49
- 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/database_configurations.rb +124 -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 +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/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 +67 -17
- data/lib/active_record/migration.rb +113 -83
- 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/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- 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/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/predicate_builder.rb +57 -33
- 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/relation.rb +90 -64
- 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/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 +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/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 +30 -31
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -115,8 +115,17 @@ module ActiveRecord
|
|
115
115
|
#
|
116
116
|
# Sets the column to sort records by when no explicit order clause is used
|
117
117
|
# during an ordered finder call. Useful when the primary key is not an
|
118
|
-
# auto-incrementing integer, for example when it's a UUID.
|
119
|
-
#
|
118
|
+
# auto-incrementing integer, for example when it's a UUID. Records are subsorted
|
119
|
+
# by the primary key if it exists to ensure deterministic results.
|
120
|
+
|
121
|
+
##
|
122
|
+
# :singleton-method: immutable_strings_by_default=
|
123
|
+
# :call-seq: immutable_strings_by_default=(bool)
|
124
|
+
#
|
125
|
+
# Determines whether columns should infer their type as `:string` or
|
126
|
+
# `:immutable_string`. This setting does not affect the behavior of
|
127
|
+
# `attribute :foo, :string`. Defaults to false.
|
128
|
+
|
120
129
|
included do
|
121
130
|
mattr_accessor :primary_key_prefix_type, instance_writer: false
|
122
131
|
|
@@ -126,12 +135,13 @@ module ActiveRecord
|
|
126
135
|
class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
|
127
136
|
class_attribute :pluralize_table_names, instance_writer: false, default: true
|
128
137
|
class_attribute :implicit_order_column, instance_accessor: false
|
138
|
+
class_attribute :immutable_strings_by_default, instance_accessor: false
|
129
139
|
|
130
140
|
self.protected_environments = ["production"]
|
131
141
|
self.inheritance_column = "type"
|
132
142
|
self.ignored_columns = [].freeze
|
133
143
|
|
134
|
-
delegate :type_for_attribute, to: :class
|
144
|
+
delegate :type_for_attribute, :column_for_attribute, to: :class
|
135
145
|
|
136
146
|
initialize_load_schema_monitor
|
137
147
|
end
|
@@ -287,37 +297,9 @@ module ActiveRecord
|
|
287
297
|
|
288
298
|
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
289
299
|
# accessors defined, and won't be referenced in SQL queries.
|
290
|
-
#
|
291
|
-
# A common usage pattern for this method is to ensure all references to an attribute
|
292
|
-
# have been removed and deployed, before a migration to drop the column from the database
|
293
|
-
# has been deployed and run. Using this two step approach to dropping columns ensures there
|
294
|
-
# is no code that raises errors due to having a cached schema in memory at the time the
|
295
|
-
# schema migration is run.
|
296
|
-
#
|
297
|
-
# For example, given a model where you want to drop the "category" attribute, first mark it
|
298
|
-
# as ignored:
|
299
|
-
#
|
300
|
-
# class Project < ActiveRecord::Base
|
301
|
-
# # schema:
|
302
|
-
# # id :bigint
|
303
|
-
# # name :string, limit: 255
|
304
|
-
# # category :string, limit: 255
|
305
|
-
#
|
306
|
-
# self.ignored_columns = [:category]
|
307
|
-
# end
|
308
|
-
#
|
309
|
-
# The schema still contains `category`, but now the model omits it, so any meta-driven code or
|
310
|
-
# schema caching will not attempt to use the column:
|
311
|
-
#
|
312
|
-
# Project.columns_hash["category"] => nil
|
313
|
-
#
|
314
|
-
# You will get an error if accessing that attribute directly, so ensure all usages of the
|
315
|
-
# column are removed (automated tests can help you find any usages).
|
316
|
-
#
|
317
|
-
# user = Project.create!(name: "First Project")
|
318
|
-
# user.category # => raises NoMethodError
|
319
300
|
def ignored_columns=(columns)
|
320
|
-
|
301
|
+
reload_schema_from_cache
|
302
|
+
@ignored_columns = columns.map(&:to_s).freeze
|
321
303
|
end
|
322
304
|
|
323
305
|
def sequence_name
|
@@ -384,7 +366,7 @@ module ActiveRecord
|
|
384
366
|
|
385
367
|
def columns
|
386
368
|
load_schema
|
387
|
-
@columns ||= columns_hash.values
|
369
|
+
@columns ||= columns_hash.values.freeze
|
388
370
|
end
|
389
371
|
|
390
372
|
def attribute_types # :nodoc:
|
@@ -409,6 +391,8 @@ module ActiveRecord
|
|
409
391
|
# a string or a symbol.
|
410
392
|
def type_for_attribute(attr_name, &block)
|
411
393
|
attr_name = attr_name.to_s
|
394
|
+
attr_name = attribute_aliases[attr_name] || attr_name
|
395
|
+
|
412
396
|
if block
|
413
397
|
attribute_types.fetch(attr_name, &block)
|
414
398
|
else
|
@@ -416,11 +400,31 @@ module ActiveRecord
|
|
416
400
|
end
|
417
401
|
end
|
418
402
|
|
403
|
+
# Returns the column object for the named attribute.
|
404
|
+
# Returns an +ActiveRecord::ConnectionAdapters::NullColumn+ if the
|
405
|
+
# named attribute does not exist.
|
406
|
+
#
|
407
|
+
# class Person < ActiveRecord::Base
|
408
|
+
# end
|
409
|
+
#
|
410
|
+
# person = Person.new
|
411
|
+
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
|
412
|
+
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
413
|
+
#
|
414
|
+
# person.column_for_attribute(:nothing)
|
415
|
+
# # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
|
416
|
+
def column_for_attribute(name)
|
417
|
+
name = name.to_s
|
418
|
+
columns_hash.fetch(name) do
|
419
|
+
ConnectionAdapters::NullColumn.new(name)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
419
423
|
# Returns a hash where the keys are column names and the values are
|
420
424
|
# default values when instantiating the Active Record object for this table.
|
421
425
|
def column_defaults
|
422
426
|
load_schema
|
423
|
-
@column_defaults ||= _default_attributes.deep_dup.to_hash
|
427
|
+
@column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
|
424
428
|
end
|
425
429
|
|
426
430
|
def _default_attributes # :nodoc:
|
@@ -430,7 +434,7 @@ module ActiveRecord
|
|
430
434
|
|
431
435
|
# Returns an array of column names as strings.
|
432
436
|
def column_names
|
433
|
-
@column_names ||= columns.map(&:name)
|
437
|
+
@column_names ||= columns.map(&:name).freeze
|
434
438
|
end
|
435
439
|
|
436
440
|
def symbol_column_to_string(name_symbol) # :nodoc:
|
@@ -444,9 +448,8 @@ module ActiveRecord
|
|
444
448
|
@content_columns ||= columns.reject do |c|
|
445
449
|
c.name == primary_key ||
|
446
450
|
c.name == inheritance_column ||
|
447
|
-
c.name.end_with?("_id")
|
448
|
-
|
449
|
-
end
|
451
|
+
c.name.end_with?("_id", "_count")
|
452
|
+
end.freeze
|
450
453
|
end
|
451
454
|
|
452
455
|
# Resets all the cached information about columns, which will cause them
|
@@ -456,7 +459,7 @@ module ActiveRecord
|
|
456
459
|
# when just after creating a table you want to populate it with some default
|
457
460
|
# values, eg:
|
458
461
|
#
|
459
|
-
# class CreateJobLevels < ActiveRecord::Migration[
|
462
|
+
# class CreateJobLevels < ActiveRecord::Migration[6.0]
|
460
463
|
# def up
|
461
464
|
# create_table :job_levels do |t|
|
462
465
|
# t.integer :id
|
@@ -514,11 +517,20 @@ module ActiveRecord
|
|
514
517
|
end
|
515
518
|
|
516
519
|
def load_schema!
|
517
|
-
|
520
|
+
unless table_name
|
521
|
+
raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
|
522
|
+
end
|
523
|
+
|
524
|
+
columns_hash = connection.schema_cache.columns_hash(table_name)
|
525
|
+
columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
|
526
|
+
@columns_hash = columns_hash.freeze
|
518
527
|
@columns_hash.each do |name, column|
|
528
|
+
type = connection.lookup_cast_type_from_column(column)
|
529
|
+
type = _convert_type_from_options(type)
|
530
|
+
warn_if_deprecated_type(column)
|
519
531
|
define_attribute(
|
520
532
|
name,
|
521
|
-
|
533
|
+
type,
|
522
534
|
default: column.default,
|
523
535
|
user_provided_default: false
|
524
536
|
)
|
@@ -567,6 +579,40 @@ module ActiveRecord
|
|
567
579
|
base_class.table_name
|
568
580
|
end
|
569
581
|
end
|
582
|
+
|
583
|
+
def _convert_type_from_options(type)
|
584
|
+
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
585
|
+
type.to_immutable_string
|
586
|
+
else
|
587
|
+
type
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
def warn_if_deprecated_type(column)
|
592
|
+
return if attributes_to_define_after_schema_loads.key?(column.name)
|
593
|
+
return unless column.respond_to?(:oid)
|
594
|
+
|
595
|
+
if column.array?
|
596
|
+
array_arguments = ", array: true"
|
597
|
+
else
|
598
|
+
array_arguments = ""
|
599
|
+
end
|
600
|
+
|
601
|
+
if column.sql_type.start_with?("interval")
|
602
|
+
precision_arguments = column.precision.presence && ", precision: #{column.precision}"
|
603
|
+
ActiveSupport::Deprecation.warn(<<~WARNING)
|
604
|
+
The behavior of the `:interval` type will be changing in Rails 6.2
|
605
|
+
to return an `ActiveSupport::Duration` object. If you'd like to keep
|
606
|
+
the old behavior, you can add this line to #{self.name} model:
|
607
|
+
|
608
|
+
attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
|
609
|
+
|
610
|
+
If you'd like the new behavior today, you can add this line:
|
611
|
+
|
612
|
+
attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
|
613
|
+
WARNING
|
614
|
+
end
|
615
|
+
end
|
570
616
|
end
|
571
617
|
end
|
572
618
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/hash/except"
|
4
4
|
require "active_support/core_ext/module/redefine_method"
|
5
|
-
require "active_support/core_ext/object/try"
|
6
5
|
require "active_support/core_ext/hash/indifferent_access"
|
7
6
|
|
8
7
|
module ActiveRecord
|
@@ -289,7 +288,7 @@ module ActiveRecord
|
|
289
288
|
# [:allow_destroy]
|
290
289
|
# If true, destroys any members from the attributes hash with a
|
291
290
|
# <tt>_destroy</tt> key and a value that evaluates to +true+
|
292
|
-
# (
|
291
|
+
# (e.g. 1, '1', true, or 'true'). This option is off by default.
|
293
292
|
# [:reject_if]
|
294
293
|
# Allows you to specify a Proc or a Symbol pointing to a method
|
295
294
|
# that checks whether a record should be built for a certain attribute
|
@@ -510,7 +509,7 @@ module ActiveRecord
|
|
510
509
|
if target_record
|
511
510
|
existing_record = target_record
|
512
511
|
else
|
513
|
-
association.add_to_target(existing_record, :
|
512
|
+
association.add_to_target(existing_record, skip_callbacks: true)
|
514
513
|
end
|
515
514
|
|
516
515
|
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
@@ -414,8 +414,8 @@ module ActiveRecord
|
|
414
414
|
|
415
415
|
def _substitute_values(values)
|
416
416
|
values.map do |name, value|
|
417
|
-
attr =
|
418
|
-
bind = predicate_builder.build_bind_attribute(name, value)
|
417
|
+
attr = arel_table[name]
|
418
|
+
bind = predicate_builder.build_bind_attribute(attr.name, value)
|
419
419
|
[attr, bind]
|
420
420
|
end
|
421
421
|
end
|
@@ -424,26 +424,30 @@ module ActiveRecord
|
|
424
424
|
# Returns true if this object hasn't been saved yet -- that is, a record
|
425
425
|
# for the object doesn't exist in the database yet; otherwise, returns false.
|
426
426
|
def new_record?
|
427
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
428
427
|
@new_record
|
429
428
|
end
|
430
429
|
|
430
|
+
# Returns true if this object was just created -- that is, prior to the last
|
431
|
+
# save, the object didn't exist in the database and new_record? would have
|
432
|
+
# returned true.
|
433
|
+
def previously_new_record?
|
434
|
+
@previously_new_record
|
435
|
+
end
|
436
|
+
|
431
437
|
# Returns true if this object has been destroyed, otherwise returns false.
|
432
438
|
def destroyed?
|
433
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
434
439
|
@destroyed
|
435
440
|
end
|
436
441
|
|
437
442
|
# Returns true if the record is persisted, i.e. it's not a new record and it was
|
438
443
|
# not destroyed, otherwise returns false.
|
439
444
|
def persisted?
|
440
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
441
445
|
!(@new_record || @destroyed)
|
442
446
|
end
|
443
447
|
|
444
448
|
##
|
445
449
|
# :call-seq:
|
446
|
-
# save(
|
450
|
+
# save(**options)
|
447
451
|
#
|
448
452
|
# Saves the model.
|
449
453
|
#
|
@@ -466,15 +470,15 @@ module ActiveRecord
|
|
466
470
|
#
|
467
471
|
# Attributes marked as readonly are silently ignored if the record is
|
468
472
|
# being updated.
|
469
|
-
def save(
|
470
|
-
create_or_update(
|
473
|
+
def save(**options, &block)
|
474
|
+
create_or_update(**options, &block)
|
471
475
|
rescue ActiveRecord::RecordInvalid
|
472
476
|
false
|
473
477
|
end
|
474
478
|
|
475
479
|
##
|
476
480
|
# :call-seq:
|
477
|
-
# save!(
|
481
|
+
# save!(**options)
|
478
482
|
#
|
479
483
|
# Saves the model.
|
480
484
|
#
|
@@ -499,8 +503,8 @@ module ActiveRecord
|
|
499
503
|
# being updated.
|
500
504
|
#
|
501
505
|
# Unless an error is raised, returns true.
|
502
|
-
def save!(
|
503
|
-
create_or_update(
|
506
|
+
def save!(**options, &block)
|
507
|
+
create_or_update(**options, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
|
504
508
|
end
|
505
509
|
|
506
510
|
# Deletes the record in the database and freezes this instance to
|
@@ -514,7 +518,7 @@ module ActiveRecord
|
|
514
518
|
#
|
515
519
|
# To enforce the object's +before_destroy+ and +after_destroy+
|
516
520
|
# callbacks or any <tt>:dependent</tt> association
|
517
|
-
# options, use
|
521
|
+
# options, use #destroy.
|
518
522
|
def delete
|
519
523
|
_delete_row if persisted?
|
520
524
|
@destroyed = true
|
@@ -565,12 +569,15 @@ module ActiveRecord
|
|
565
569
|
# If you want to change the sti column as well, use #becomes! instead.
|
566
570
|
def becomes(klass)
|
567
571
|
became = klass.allocate
|
568
|
-
|
569
|
-
became.
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
572
|
+
|
573
|
+
became.send(:initialize) do |becoming|
|
574
|
+
becoming.instance_variable_set(:@attributes, @attributes)
|
575
|
+
becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
|
576
|
+
becoming.instance_variable_set(:@new_record, new_record?)
|
577
|
+
becoming.instance_variable_set(:@destroyed, destroyed?)
|
578
|
+
becoming.errors.copy!(errors)
|
579
|
+
end
|
580
|
+
|
574
581
|
became
|
575
582
|
end
|
576
583
|
|
@@ -622,9 +629,6 @@ module ActiveRecord
|
|
622
629
|
end
|
623
630
|
end
|
624
631
|
|
625
|
-
alias update_attributes update
|
626
|
-
deprecate update_attributes: "please, use update instead"
|
627
|
-
|
628
632
|
# Updates its receiver just like #update but calls #save! instead
|
629
633
|
# of +save+, so an exception is raised if the record is invalid and saving will fail.
|
630
634
|
def update!(attributes)
|
@@ -636,9 +640,6 @@ module ActiveRecord
|
|
636
640
|
end
|
637
641
|
end
|
638
642
|
|
639
|
-
alias update_attributes! update!
|
640
|
-
deprecate update_attributes!: "please, use update! instead"
|
641
|
-
|
642
643
|
# Equivalent to <code>update_columns(name => value)</code>.
|
643
644
|
def update_column(name, value)
|
644
645
|
update_columns(name => value)
|
@@ -666,11 +667,8 @@ module ActiveRecord
|
|
666
667
|
|
667
668
|
attributes = attributes.transform_keys do |key|
|
668
669
|
name = key.to_s
|
669
|
-
self.class.attribute_aliases[name] || name
|
670
|
-
|
671
|
-
|
672
|
-
attributes.each_key do |key|
|
673
|
-
verify_readonly_attribute(key)
|
670
|
+
name = self.class.attribute_aliases[name] || name
|
671
|
+
verify_readonly_attribute(name) || name
|
674
672
|
end
|
675
673
|
|
676
674
|
id_in_database = self.id_in_database
|
@@ -703,9 +701,9 @@ module ActiveRecord
|
|
703
701
|
# Returns +self+.
|
704
702
|
def increment!(attribute, by = 1, touch: nil)
|
705
703
|
increment(attribute, by)
|
706
|
-
change = public_send(attribute) - (
|
704
|
+
change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
|
707
705
|
self.class.update_counters(id, attribute => change, touch: touch)
|
708
|
-
|
706
|
+
public_send(:"clear_#{attribute}_change")
|
709
707
|
self
|
710
708
|
end
|
711
709
|
|
@@ -809,8 +807,9 @@ module ActiveRecord
|
|
809
807
|
self.class.unscoped { self.class.find(id) }
|
810
808
|
end
|
811
809
|
|
812
|
-
@attributes = fresh_object.instance_variable_get(
|
810
|
+
@attributes = fresh_object.instance_variable_get(:@attributes)
|
813
811
|
@new_record = false
|
812
|
+
@previously_new_record = false
|
814
813
|
self
|
815
814
|
end
|
816
815
|
|
@@ -849,17 +848,13 @@ module ActiveRecord
|
|
849
848
|
# ball.touch(:updated_at) # => raises ActiveRecordError
|
850
849
|
#
|
851
850
|
def touch(*names, time: nil)
|
852
|
-
unless persisted?
|
853
|
-
raise ActiveRecordError, <<-MSG.squish
|
854
|
-
cannot touch on a new or destroyed record object. Consider using
|
855
|
-
persisted?, new_record?, or destroyed? before touching
|
856
|
-
MSG
|
857
|
-
end
|
851
|
+
_raise_record_not_touched_error unless persisted?
|
858
852
|
|
859
853
|
attribute_names = timestamp_attributes_for_update_in_model
|
860
|
-
attribute_names |= names.map!
|
854
|
+
attribute_names |= names.map! do |name|
|
855
|
+
name = name.to_s
|
861
856
|
self.class.attribute_aliases[name] || name
|
862
|
-
|
857
|
+
end unless names.empty?
|
863
858
|
|
864
859
|
unless attribute_names.empty?
|
865
860
|
affected_rows = _touch_row(attribute_names, time)
|
@@ -919,6 +914,8 @@ module ActiveRecord
|
|
919
914
|
@_trigger_update_callback = affected_rows == 1
|
920
915
|
end
|
921
916
|
|
917
|
+
@previously_new_record = false
|
918
|
+
|
922
919
|
yield(self) if block_given?
|
923
920
|
|
924
921
|
affected_rows
|
@@ -936,6 +933,7 @@ module ActiveRecord
|
|
936
933
|
self.id ||= new_id if @primary_key
|
937
934
|
|
938
935
|
@new_record = false
|
936
|
+
@previously_new_record = true
|
939
937
|
|
940
938
|
yield(self) if block_given?
|
941
939
|
|
@@ -943,7 +941,7 @@ module ActiveRecord
|
|
943
941
|
end
|
944
942
|
|
945
943
|
def verify_readonly_attribute(name)
|
946
|
-
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.
|
944
|
+
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
|
947
945
|
end
|
948
946
|
|
949
947
|
def _raise_record_not_destroyed
|
@@ -953,14 +951,21 @@ module ActiveRecord
|
|
953
951
|
@_association_destroy_exception = nil
|
954
952
|
end
|
955
953
|
|
954
|
+
def _raise_readonly_record_error
|
955
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly"
|
956
|
+
end
|
957
|
+
|
958
|
+
def _raise_record_not_touched_error
|
959
|
+
raise ActiveRecordError, <<~MSG.squish
|
960
|
+
Cannot touch on a new or destroyed record object. Consider using
|
961
|
+
persisted?, new_record?, or destroyed? before touching.
|
962
|
+
MSG
|
963
|
+
end
|
964
|
+
|
956
965
|
# The name of the method used to touch a +belongs_to+ association when the
|
957
966
|
# +:touch+ option is used.
|
958
967
|
def belongs_to_touch_method
|
959
968
|
:touch
|
960
969
|
end
|
961
|
-
|
962
|
-
def _raise_readonly_record_error
|
963
|
-
raise ReadOnlyRecord, "#{self.class} is marked as readonly"
|
964
|
-
end
|
965
970
|
end
|
966
971
|
end
|
@@ -28,18 +28,28 @@ module ActiveRecord
|
|
28
28
|
def self.run
|
29
29
|
pools = []
|
30
30
|
|
31
|
-
ActiveRecord::Base.
|
32
|
-
|
31
|
+
if ActiveRecord::Base.legacy_connection_handling
|
32
|
+
ActiveRecord::Base.connection_handlers.each do |key, handler|
|
33
|
+
pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
34
|
+
end
|
35
|
+
else
|
36
|
+
pools.concat(ActiveRecord::Base.connection_handler.all_connection_pools.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
33
37
|
end
|
34
38
|
|
35
|
-
pools
|
39
|
+
pools
|
36
40
|
end
|
37
41
|
|
38
42
|
def self.complete(pools)
|
39
43
|
pools.each { |pool| pool.disable_query_cache! }
|
40
44
|
|
41
|
-
ActiveRecord::Base.
|
42
|
-
|
45
|
+
if ActiveRecord::Base.legacy_connection_handling
|
46
|
+
ActiveRecord::Base.connection_handlers.each do |_, handler|
|
47
|
+
handler.connection_pool_list.each do |pool|
|
48
|
+
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
else
|
52
|
+
ActiveRecord::Base.connection_handler.all_connection_pools.each do |pool|
|
43
53
|
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
44
54
|
end
|
45
55
|
end
|
@@ -13,10 +13,11 @@ module ActiveRecord
|
|
13
13
|
:destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
|
14
14
|
:find_each, :find_in_batches, :in_batches,
|
15
15
|
:select, :reselect, :order, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
|
16
|
-
:where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
16
|
+
:where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
|
17
|
+
:and, :or, :annotate, :optimizer_hints, :extending,
|
18
|
+
:having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
|
19
|
+
:count, :average, :minimum, :maximum, :sum, :calculate,
|
20
|
+
:pluck, :pick, :ids, :strict_loading
|
20
21
|
].freeze # :nodoc:
|
21
22
|
delegate(*QUERYING_METHODS, to: :all)
|
22
23
|
|
@@ -44,8 +45,12 @@ module ActiveRecord
|
|
44
45
|
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
|
45
46
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
46
47
|
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
|
47
|
-
column_types = result_set.column_types
|
48
|
-
|
48
|
+
column_types = result_set.column_types
|
49
|
+
|
50
|
+
unless column_types.empty?
|
51
|
+
column_types = column_types.reject { |k, _| attribute_types.key?(k) }
|
52
|
+
end
|
53
|
+
|
49
54
|
message_bus = ActiveSupport::Notifications.instrumenter
|
50
55
|
|
51
56
|
payload = {
|