activerecord 6.0.1 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +843 -626
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +18 -17
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -37
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- 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 +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- 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 +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +115 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +56 -41
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +60 -73
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- 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/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +28 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- 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 +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- 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 +19 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- 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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +77 -57
- 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 +36 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -87
- data/lib/active_record/core.rb +229 -65
- data/lib/active_record/counter_cache.rb +4 -1
- 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 -41
- 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/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- 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 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +38 -9
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +117 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +45 -16
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- data/lib/active_record/relation/query_methods.rb +335 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/relation.rb +108 -68
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- 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 +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +21 -70
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -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/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -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/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 +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -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 +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +26 -26
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- 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 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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,8 +297,38 @@ 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.
|
300
|
+
#
|
301
|
+
# A common usage pattern for this method is to ensure all references to an attribute
|
302
|
+
# have been removed and deployed, before a migration to drop the column from the database
|
303
|
+
# has been deployed and run. Using this two step approach to dropping columns ensures there
|
304
|
+
# is no code that raises errors due to having a cached schema in memory at the time the
|
305
|
+
# schema migration is run.
|
306
|
+
#
|
307
|
+
# For example, given a model where you want to drop the "category" attribute, first mark it
|
308
|
+
# as ignored:
|
309
|
+
#
|
310
|
+
# class Project < ActiveRecord::Base
|
311
|
+
# # schema:
|
312
|
+
# # id :bigint
|
313
|
+
# # name :string, limit: 255
|
314
|
+
# # category :string, limit: 255
|
315
|
+
#
|
316
|
+
# self.ignored_columns = [:category]
|
317
|
+
# end
|
318
|
+
#
|
319
|
+
# The schema still contains `category`, but now the model omits it, so any meta-driven code or
|
320
|
+
# schema caching will not attempt to use the column:
|
321
|
+
#
|
322
|
+
# Project.columns_hash["category"] => nil
|
323
|
+
#
|
324
|
+
# You will get an error if accessing that attribute directly, so ensure all usages of the
|
325
|
+
# column are removed (automated tests can help you find any usages).
|
326
|
+
#
|
327
|
+
# user = Project.create!(name: "First Project")
|
328
|
+
# user.category # => raises NoMethodError
|
290
329
|
def ignored_columns=(columns)
|
291
|
-
|
330
|
+
reload_schema_from_cache
|
331
|
+
@ignored_columns = columns.map(&:to_s).freeze
|
292
332
|
end
|
293
333
|
|
294
334
|
def sequence_name
|
@@ -355,7 +395,7 @@ module ActiveRecord
|
|
355
395
|
|
356
396
|
def columns
|
357
397
|
load_schema
|
358
|
-
@columns ||= columns_hash.values
|
398
|
+
@columns ||= columns_hash.values.freeze
|
359
399
|
end
|
360
400
|
|
361
401
|
def attribute_types # :nodoc:
|
@@ -380,6 +420,8 @@ module ActiveRecord
|
|
380
420
|
# a string or a symbol.
|
381
421
|
def type_for_attribute(attr_name, &block)
|
382
422
|
attr_name = attr_name.to_s
|
423
|
+
attr_name = attribute_aliases[attr_name] || attr_name
|
424
|
+
|
383
425
|
if block
|
384
426
|
attribute_types.fetch(attr_name, &block)
|
385
427
|
else
|
@@ -387,11 +429,31 @@ module ActiveRecord
|
|
387
429
|
end
|
388
430
|
end
|
389
431
|
|
432
|
+
# Returns the column object for the named attribute.
|
433
|
+
# Returns an +ActiveRecord::ConnectionAdapters::NullColumn+ if the
|
434
|
+
# named attribute does not exist.
|
435
|
+
#
|
436
|
+
# class Person < ActiveRecord::Base
|
437
|
+
# end
|
438
|
+
#
|
439
|
+
# person = Person.new
|
440
|
+
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
|
441
|
+
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
442
|
+
#
|
443
|
+
# person.column_for_attribute(:nothing)
|
444
|
+
# # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
|
445
|
+
def column_for_attribute(name)
|
446
|
+
name = name.to_s
|
447
|
+
columns_hash.fetch(name) do
|
448
|
+
ConnectionAdapters::NullColumn.new(name)
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
390
452
|
# Returns a hash where the keys are column names and the values are
|
391
453
|
# default values when instantiating the Active Record object for this table.
|
392
454
|
def column_defaults
|
393
455
|
load_schema
|
394
|
-
@column_defaults ||= _default_attributes.deep_dup.to_hash
|
456
|
+
@column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
|
395
457
|
end
|
396
458
|
|
397
459
|
def _default_attributes # :nodoc:
|
@@ -401,7 +463,7 @@ module ActiveRecord
|
|
401
463
|
|
402
464
|
# Returns an array of column names as strings.
|
403
465
|
def column_names
|
404
|
-
@column_names ||= columns.map(&:name)
|
466
|
+
@column_names ||= columns.map(&:name).freeze
|
405
467
|
end
|
406
468
|
|
407
469
|
def symbol_column_to_string(name_symbol) # :nodoc:
|
@@ -415,9 +477,8 @@ module ActiveRecord
|
|
415
477
|
@content_columns ||= columns.reject do |c|
|
416
478
|
c.name == primary_key ||
|
417
479
|
c.name == inheritance_column ||
|
418
|
-
c.name.end_with?("_id")
|
419
|
-
|
420
|
-
end
|
480
|
+
c.name.end_with?("_id", "_count")
|
481
|
+
end.freeze
|
421
482
|
end
|
422
483
|
|
423
484
|
# Resets all the cached information about columns, which will cause them
|
@@ -427,7 +488,7 @@ module ActiveRecord
|
|
427
488
|
# when just after creating a table you want to populate it with some default
|
428
489
|
# values, eg:
|
429
490
|
#
|
430
|
-
# class CreateJobLevels < ActiveRecord::Migration[
|
491
|
+
# class CreateJobLevels < ActiveRecord::Migration[6.0]
|
431
492
|
# def up
|
432
493
|
# create_table :job_levels do |t|
|
433
494
|
# t.integer :id
|
@@ -456,13 +517,11 @@ module ActiveRecord
|
|
456
517
|
end
|
457
518
|
|
458
519
|
protected
|
459
|
-
|
460
520
|
def initialize_load_schema_monitor
|
461
521
|
@load_schema_monitor = Monitor.new
|
462
522
|
end
|
463
523
|
|
464
524
|
private
|
465
|
-
|
466
525
|
def inherited(child_class)
|
467
526
|
super
|
468
527
|
child_class.initialize_load_schema_monitor
|
@@ -487,11 +546,20 @@ module ActiveRecord
|
|
487
546
|
end
|
488
547
|
|
489
548
|
def load_schema!
|
490
|
-
|
549
|
+
unless table_name
|
550
|
+
raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
|
551
|
+
end
|
552
|
+
|
553
|
+
columns_hash = connection.schema_cache.columns_hash(table_name)
|
554
|
+
columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
|
555
|
+
@columns_hash = columns_hash.freeze
|
491
556
|
@columns_hash.each do |name, column|
|
557
|
+
type = connection.lookup_cast_type_from_column(column)
|
558
|
+
type = _convert_type_from_options(type)
|
559
|
+
warn_if_deprecated_type(column)
|
492
560
|
define_attribute(
|
493
561
|
name,
|
494
|
-
|
562
|
+
type,
|
495
563
|
default: column.default,
|
496
564
|
user_provided_default: false
|
497
565
|
)
|
@@ -540,6 +608,40 @@ module ActiveRecord
|
|
540
608
|
base_class.table_name
|
541
609
|
end
|
542
610
|
end
|
611
|
+
|
612
|
+
def _convert_type_from_options(type)
|
613
|
+
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
614
|
+
type.to_immutable_string
|
615
|
+
else
|
616
|
+
type
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
def warn_if_deprecated_type(column)
|
621
|
+
return if attributes_to_define_after_schema_loads.key?(column.name)
|
622
|
+
return unless column.respond_to?(:oid)
|
623
|
+
|
624
|
+
if column.array?
|
625
|
+
array_arguments = ", array: true"
|
626
|
+
else
|
627
|
+
array_arguments = ""
|
628
|
+
end
|
629
|
+
|
630
|
+
if column.sql_type.start_with?("interval")
|
631
|
+
precision_arguments = column.precision.presence && ", precision: #{column.precision}"
|
632
|
+
ActiveSupport::Deprecation.warn(<<~WARNING)
|
633
|
+
The behavior of the `:interval` type will be changing in Rails 6.2
|
634
|
+
to return an `ActiveSupport::Duration` object. If you'd like to keep
|
635
|
+
the old behavior, you can add this line to #{self.name} model:
|
636
|
+
|
637
|
+
attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
|
638
|
+
|
639
|
+
If you'd like the new behavior today, you can add this line:
|
640
|
+
|
641
|
+
attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
|
642
|
+
WARNING
|
643
|
+
end
|
644
|
+
end
|
543
645
|
end
|
544
646
|
end
|
545
647
|
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
|
@@ -354,7 +353,6 @@ module ActiveRecord
|
|
354
353
|
end
|
355
354
|
|
356
355
|
private
|
357
|
-
|
358
356
|
# Generates a writer method for this association. Serves as a point for
|
359
357
|
# accessing the objects in the association. For example, this method
|
360
358
|
# could generate the following:
|
@@ -386,7 +384,6 @@ module ActiveRecord
|
|
386
384
|
end
|
387
385
|
|
388
386
|
private
|
389
|
-
|
390
387
|
# Attribute hash keys that should not be assigned as normal attributes.
|
391
388
|
# These hash keys are nested attributes implementation details.
|
392
389
|
UNASSIGNABLE_KEYS = %w( id _destroy )
|
@@ -512,7 +509,7 @@ module ActiveRecord
|
|
512
509
|
if target_record
|
513
510
|
existing_record = target_record
|
514
511
|
else
|
515
|
-
association.add_to_target(existing_record, :
|
512
|
+
association.add_to_target(existing_record, skip_callbacks: true)
|
516
513
|
end
|
517
514
|
|
518
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)
|
@@ -870,7 +865,6 @@ module ActiveRecord
|
|
870
865
|
end
|
871
866
|
|
872
867
|
private
|
873
|
-
|
874
868
|
# A hook to be overridden by association modules.
|
875
869
|
def destroy_associations
|
876
870
|
end
|
@@ -920,6 +914,8 @@ module ActiveRecord
|
|
920
914
|
@_trigger_update_callback = affected_rows == 1
|
921
915
|
end
|
922
916
|
|
917
|
+
@previously_new_record = false
|
918
|
+
|
923
919
|
yield(self) if block_given?
|
924
920
|
|
925
921
|
affected_rows
|
@@ -937,6 +933,7 @@ module ActiveRecord
|
|
937
933
|
self.id ||= new_id if @primary_key
|
938
934
|
|
939
935
|
@new_record = false
|
936
|
+
@previously_new_record = true
|
940
937
|
|
941
938
|
yield(self) if block_given?
|
942
939
|
|
@@ -944,7 +941,7 @@ module ActiveRecord
|
|
944
941
|
end
|
945
942
|
|
946
943
|
def verify_readonly_attribute(name)
|
947
|
-
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.
|
944
|
+
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
|
948
945
|
end
|
949
946
|
|
950
947
|
def _raise_record_not_destroyed
|
@@ -954,14 +951,21 @@ module ActiveRecord
|
|
954
951
|
@_association_destroy_exception = nil
|
955
952
|
end
|
956
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
|
+
|
957
965
|
# The name of the method used to touch a +belongs_to+ association when the
|
958
966
|
# +:touch+ option is used.
|
959
967
|
def belongs_to_touch_method
|
960
968
|
:touch
|
961
969
|
end
|
962
|
-
|
963
|
-
def _raise_readonly_record_error
|
964
|
-
raise ReadOnlyRecord, "#{self.class} is marked as readonly"
|
965
|
-
end
|
966
970
|
end
|
967
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
|
|
@@ -36,7 +37,7 @@ module ActiveRecord
|
|
36
37
|
#
|
37
38
|
# # A simple SQL query spanning multiple tables
|
38
39
|
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
39
|
-
# # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "
|
40
|
+
# # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "author"=>"Quentin"}>, ...]
|
40
41
|
#
|
41
42
|
# You can use the same string replacement techniques as you can with <tt>ActiveRecord::QueryMethods#where</tt>:
|
42
43
|
#
|
@@ -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 = {
|