activerecord 7.0.0 → 7.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +515 -1268
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +28 -17
- data/lib/active_record/associations/collection_proxy.rb +36 -13
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +18 -14
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +2 -4
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +378 -491
- data/lib/active_record/attribute_assignment.rb +1 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +153 -70
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +153 -40
- data/lib/active_record/attributes.rb +63 -48
- data/lib/active_record/autosave_association.rb +70 -38
- data/lib/active_record/base.rb +12 -8
- data/lib/active_record/callbacks.rb +16 -32
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -34
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +124 -132
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +297 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +215 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +83 -65
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +163 -29
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +319 -135
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +512 -126
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +282 -119
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +27 -140
- data/lib/active_record/connection_adapters/mysql/quoting.rb +64 -52
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +101 -48
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +94 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +379 -66
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +370 -203
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +61 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +64 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +321 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +98 -106
- data/lib/active_record/core.rb +220 -177
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -2
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +88 -35
- data/lib/active_record/delegated_type.rb +40 -11
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +13 -14
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +8 -4
- data/lib/active_record/encryption/derived_secret_key_provider.rb +9 -3
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +47 -25
- data/lib/active_record/encryption/encrypted_attribute_type.rb +49 -14
- data/lib/active_record/encryption/encryptor.rb +25 -10
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +83 -86
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +4 -4
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +23 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +131 -27
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +169 -99
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +39 -24
- data/lib/active_record/locking/pessimistic.rb +8 -5
- data/lib/active_record/log_subscriber.rb +28 -27
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +18 -13
- data/lib/active_record/middleware/shard_selector.rb +7 -5
- data/lib/active_record/migration/command_recorder.rb +110 -13
- data/lib/active_record/migration/compatibility.rb +174 -64
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +292 -125
- data/lib/active_record/model_schema.rb +113 -112
- data/lib/active_record/nested_attributes.rb +35 -9
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +177 -345
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +102 -51
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +34 -9
- data/lib/active_record/railtie.rb +153 -100
- data/lib/active_record/railties/controller_runtime.rb +24 -10
- data/lib/active_record/railties/databases.rake +148 -152
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +278 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +293 -108
- data/lib/active_record/relation/delegation.rb +31 -20
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +625 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +602 -96
- data/lib/active_record/result.rb +55 -52
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +76 -30
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +82 -30
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +20 -12
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +29 -8
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +16 -11
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +191 -121
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +17 -15
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +174 -152
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +109 -27
- data/lib/active_record/translation.rb +1 -3
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +12 -6
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +63 -14
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +266 -30
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +59 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
|
@@ -57,281 +57,34 @@ module ActiveRecord
|
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# Active Record callbacks or validations. Though passed values
|
|
63
|
-
# go through Active Record's type casting and serialization.
|
|
60
|
+
# Builds an object (or multiple objects) and returns either the built object or a list of built
|
|
61
|
+
# objects.
|
|
64
62
|
#
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Inserts multiple records into the database in a single SQL INSERT
|
|
71
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
72
|
-
# Active Record callbacks or validations. Though passed values
|
|
73
|
-
# go through Active Record's type casting and serialization.
|
|
74
|
-
#
|
|
75
|
-
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
|
76
|
-
# the attributes for a single row and must have the same keys.
|
|
77
|
-
#
|
|
78
|
-
# Rows are considered to be unique by every unique index on the table. Any
|
|
79
|
-
# duplicate rows are skipped.
|
|
80
|
-
# Override with <tt>:unique_by</tt> (see below).
|
|
81
|
-
#
|
|
82
|
-
# Returns an <tt>ActiveRecord::Result</tt> with its contents based on
|
|
83
|
-
# <tt>:returning</tt> (see below).
|
|
84
|
-
#
|
|
85
|
-
# ==== Options
|
|
86
|
-
#
|
|
87
|
-
# [:returning]
|
|
88
|
-
# (PostgreSQL only) An array of attributes to return for all successfully
|
|
89
|
-
# inserted records, which by default is the primary key.
|
|
90
|
-
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
91
|
-
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
92
|
-
# clause entirely.
|
|
93
|
-
#
|
|
94
|
-
# You can also pass an SQL string if you need more control on the return values
|
|
95
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
|
96
|
-
#
|
|
97
|
-
# [:unique_by]
|
|
98
|
-
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
|
99
|
-
# by every unique index on the table. Any duplicate rows are skipped.
|
|
100
|
-
#
|
|
101
|
-
# To skip rows according to just one unique index pass <tt>:unique_by</tt>.
|
|
102
|
-
#
|
|
103
|
-
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
|
104
|
-
# row has an existing id, or is not unique by another unique index,
|
|
105
|
-
# <tt>ActiveRecord::RecordNotUnique</tt> is raised.
|
|
106
|
-
#
|
|
107
|
-
# Unique indexes can be identified by columns or name:
|
|
108
|
-
#
|
|
109
|
-
# unique_by: :isbn
|
|
110
|
-
# unique_by: %i[ author_id name ]
|
|
111
|
-
# unique_by: :index_books_on_isbn
|
|
112
|
-
#
|
|
113
|
-
# [:record_timestamps]
|
|
114
|
-
# By default, automatic setting of timestamp columns is controlled by
|
|
115
|
-
# the model's <tt>record_timestamps</tt> config, matching typical
|
|
116
|
-
# behavior.
|
|
117
|
-
#
|
|
118
|
-
# To override this and force automatic setting of timestamp columns one
|
|
119
|
-
# way or the other, pass <tt>:record_timestamps</tt>:
|
|
120
|
-
#
|
|
121
|
-
# record_timestamps: true # Always set timestamps automatically
|
|
122
|
-
# record_timestamps: false # Never set timestamps automatically
|
|
123
|
-
#
|
|
124
|
-
# Because it relies on the index information from the database
|
|
125
|
-
# <tt>:unique_by</tt> is recommended to be paired with
|
|
126
|
-
# Active Record's schema_cache.
|
|
127
|
-
#
|
|
128
|
-
# ==== Example
|
|
129
|
-
#
|
|
130
|
-
# # Insert records and skip inserting any duplicates.
|
|
131
|
-
# # Here "Eloquent Ruby" is skipped because its id is not unique.
|
|
132
|
-
#
|
|
133
|
-
# Book.insert_all([
|
|
134
|
-
# { id: 1, title: "Rework", author: "David" },
|
|
135
|
-
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
|
136
|
-
# ])
|
|
137
|
-
#
|
|
138
|
-
# # insert_all works on chained scopes, and you can use create_with
|
|
139
|
-
# # to set default attributes for all inserted records.
|
|
140
|
-
#
|
|
141
|
-
# author.books.create_with(created_at: Time.now).insert_all([
|
|
142
|
-
# { id: 1, title: "Rework" },
|
|
143
|
-
# { id: 2, title: "Eloquent Ruby" }
|
|
144
|
-
# ])
|
|
145
|
-
def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
|
|
146
|
-
InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Inserts a single record into the database in a single SQL INSERT
|
|
150
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
151
|
-
# Active Record callbacks or validations. Though passed values
|
|
152
|
-
# go through Active Record's type casting and serialization.
|
|
153
|
-
#
|
|
154
|
-
# See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
|
|
155
|
-
def insert!(attributes, returning: nil, record_timestamps: nil)
|
|
156
|
-
insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# Inserts multiple records into the database in a single SQL INSERT
|
|
160
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
161
|
-
# Active Record callbacks or validations. Though passed values
|
|
162
|
-
# go through Active Record's type casting and serialization.
|
|
163
|
-
#
|
|
164
|
-
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
|
165
|
-
# the attributes for a single row and must have the same keys.
|
|
166
|
-
#
|
|
167
|
-
# Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
|
|
168
|
-
# unique index on the table. In that case, no rows are inserted.
|
|
169
|
-
#
|
|
170
|
-
# To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
|
|
171
|
-
# To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
|
|
172
|
-
#
|
|
173
|
-
# Returns an <tt>ActiveRecord::Result</tt> with its contents based on
|
|
174
|
-
# <tt>:returning</tt> (see below).
|
|
175
|
-
#
|
|
176
|
-
# ==== Options
|
|
177
|
-
#
|
|
178
|
-
# [:returning]
|
|
179
|
-
# (PostgreSQL only) An array of attributes to return for all successfully
|
|
180
|
-
# inserted records, which by default is the primary key.
|
|
181
|
-
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
182
|
-
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
183
|
-
# clause entirely.
|
|
184
|
-
#
|
|
185
|
-
# You can also pass an SQL string if you need more control on the return values
|
|
186
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
|
187
|
-
#
|
|
188
|
-
# [:record_timestamps]
|
|
189
|
-
# By default, automatic setting of timestamp columns is controlled by
|
|
190
|
-
# the model's <tt>record_timestamps</tt> config, matching typical
|
|
191
|
-
# behavior.
|
|
192
|
-
#
|
|
193
|
-
# To override this and force automatic setting of timestamp columns one
|
|
194
|
-
# way or the other, pass <tt>:record_timestamps</tt>:
|
|
195
|
-
#
|
|
196
|
-
# record_timestamps: true # Always set timestamps automatically
|
|
197
|
-
# record_timestamps: false # Never set timestamps automatically
|
|
198
|
-
#
|
|
199
|
-
# ==== Examples
|
|
200
|
-
#
|
|
201
|
-
# # Insert multiple records
|
|
202
|
-
# Book.insert_all!([
|
|
203
|
-
# { title: "Rework", author: "David" },
|
|
204
|
-
# { title: "Eloquent Ruby", author: "Russ" }
|
|
205
|
-
# ])
|
|
206
|
-
#
|
|
207
|
-
# # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
|
|
208
|
-
# # does not have a unique id.
|
|
209
|
-
# Book.insert_all!([
|
|
210
|
-
# { id: 1, title: "Rework", author: "David" },
|
|
211
|
-
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
|
212
|
-
# ])
|
|
213
|
-
def insert_all!(attributes, returning: nil, record_timestamps: nil)
|
|
214
|
-
InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
# Updates or inserts (upserts) a single record into the database in a
|
|
218
|
-
# single SQL INSERT statement. It does not instantiate any models nor does
|
|
219
|
-
# it trigger Active Record callbacks or validations. Though passed values
|
|
220
|
-
# go through Active Record's type casting and serialization.
|
|
221
|
-
#
|
|
222
|
-
# See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
|
|
223
|
-
def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil, record_timestamps: nil)
|
|
224
|
-
upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
# Updates or inserts (upserts) multiple records into the database in a
|
|
228
|
-
# single SQL INSERT statement. It does not instantiate any models nor does
|
|
229
|
-
# it trigger Active Record callbacks or validations. Though passed values
|
|
230
|
-
# go through Active Record's type casting and serialization.
|
|
231
|
-
#
|
|
232
|
-
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
|
233
|
-
# the attributes for a single row and must have the same keys.
|
|
234
|
-
#
|
|
235
|
-
# Returns an <tt>ActiveRecord::Result</tt> with its contents based on
|
|
236
|
-
# <tt>:returning</tt> (see below).
|
|
237
|
-
#
|
|
238
|
-
# By default, +upsert_all+ will update all the columns that can be updated when
|
|
239
|
-
# there is a conflict. These are all the columns except primary keys, read-only
|
|
240
|
-
# columns, and columns covered by the optional +unique_by+.
|
|
241
|
-
#
|
|
242
|
-
# ==== Options
|
|
243
|
-
#
|
|
244
|
-
# [:returning]
|
|
245
|
-
# (PostgreSQL only) An array of attributes to return for all successfully
|
|
246
|
-
# inserted records, which by default is the primary key.
|
|
247
|
-
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
248
|
-
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
249
|
-
# clause entirely.
|
|
250
|
-
#
|
|
251
|
-
# You can also pass an SQL string if you need more control on the return values
|
|
252
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
|
253
|
-
#
|
|
254
|
-
# [:unique_by]
|
|
255
|
-
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
|
256
|
-
# by every unique index on the table. Any duplicate rows are skipped.
|
|
257
|
-
#
|
|
258
|
-
# To skip rows according to just one unique index pass <tt>:unique_by</tt>.
|
|
259
|
-
#
|
|
260
|
-
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
|
261
|
-
# row has an existing id, or is not unique by another unique index,
|
|
262
|
-
# <tt>ActiveRecord::RecordNotUnique</tt> is raised.
|
|
263
|
-
#
|
|
264
|
-
# Unique indexes can be identified by columns or name:
|
|
265
|
-
#
|
|
266
|
-
# unique_by: :isbn
|
|
267
|
-
# unique_by: %i[ author_id name ]
|
|
268
|
-
# unique_by: :index_books_on_isbn
|
|
269
|
-
#
|
|
270
|
-
# Because it relies on the index information from the database
|
|
271
|
-
# <tt>:unique_by</tt> is recommended to be paired with
|
|
272
|
-
# Active Record's schema_cache.
|
|
273
|
-
#
|
|
274
|
-
# [:on_duplicate]
|
|
275
|
-
# Configure the SQL update sentence that will be used in case of conflict.
|
|
276
|
-
#
|
|
277
|
-
# NOTE: If you use this option you must provide all the columns you want to update
|
|
278
|
-
# by yourself.
|
|
279
|
-
#
|
|
280
|
-
# Example:
|
|
281
|
-
#
|
|
282
|
-
# Commodity.upsert_all(
|
|
283
|
-
# [
|
|
284
|
-
# { id: 2, name: "Copper", price: 4.84 },
|
|
285
|
-
# { id: 4, name: "Gold", price: 1380.87 },
|
|
286
|
-
# { id: 6, name: "Aluminium", price: 0.35 }
|
|
287
|
-
# ],
|
|
288
|
-
# on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
|
|
289
|
-
# )
|
|
290
|
-
#
|
|
291
|
-
# See the related +:update_only+ option. Both options can't be used at the same time.
|
|
292
|
-
#
|
|
293
|
-
# [:update_only]
|
|
294
|
-
# Provide a list of column names that will be updated in case of conflict. If not provided,
|
|
295
|
-
# +upsert_all+ will update all the columns that can be updated. These are all the columns
|
|
296
|
-
# except primary keys, read-only columns, and columns covered by the optional +unique_by+
|
|
297
|
-
#
|
|
298
|
-
# Example:
|
|
299
|
-
#
|
|
300
|
-
# Commodity.upsert_all(
|
|
301
|
-
# [
|
|
302
|
-
# { id: 2, name: "Copper", price: 4.84 },
|
|
303
|
-
# { id: 4, name: "Gold", price: 1380.87 },
|
|
304
|
-
# { id: 6, name: "Aluminium", price: 0.35 }
|
|
305
|
-
# ],
|
|
306
|
-
# update_only: [:price] # Only prices will be updated
|
|
307
|
-
# )
|
|
308
|
-
#
|
|
309
|
-
# See the related +:on_duplicate+ option. Both options can't be used at the same time.
|
|
310
|
-
#
|
|
311
|
-
# [:record_timestamps]
|
|
312
|
-
# By default, automatic setting of timestamp columns is controlled by
|
|
313
|
-
# the model's <tt>record_timestamps</tt> config, matching typical
|
|
314
|
-
# behavior.
|
|
315
|
-
#
|
|
316
|
-
# To override this and force automatic setting of timestamp columns one
|
|
317
|
-
# way or the other, pass <tt>:record_timestamps</tt>:
|
|
318
|
-
#
|
|
319
|
-
# record_timestamps: true # Always set timestamps automatically
|
|
320
|
-
# record_timestamps: false # Never set timestamps automatically
|
|
63
|
+
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
|
|
64
|
+
# attributes on the objects that are to be built.
|
|
321
65
|
#
|
|
322
66
|
# ==== Examples
|
|
67
|
+
# # Build a single new object
|
|
68
|
+
# User.build(first_name: 'Jamie')
|
|
323
69
|
#
|
|
324
|
-
# #
|
|
325
|
-
#
|
|
70
|
+
# # Build an Array of new objects
|
|
71
|
+
# User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
|
|
326
72
|
#
|
|
327
|
-
#
|
|
328
|
-
#
|
|
329
|
-
#
|
|
330
|
-
#
|
|
73
|
+
# # Build a single object and pass it into a block to set other attributes.
|
|
74
|
+
# User.build(first_name: 'Jamie') do |u|
|
|
75
|
+
# u.is_admin = false
|
|
76
|
+
# end
|
|
331
77
|
#
|
|
332
|
-
#
|
|
333
|
-
|
|
334
|
-
|
|
78
|
+
# # Building an Array of new objects using a block, where the block is executed for each object:
|
|
79
|
+
# User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
|
|
80
|
+
# u.is_admin = false
|
|
81
|
+
# end
|
|
82
|
+
def build(attributes = nil, &block)
|
|
83
|
+
if attributes.is_a?(Array)
|
|
84
|
+
attributes.collect { |attr| build(attr, &block) }
|
|
85
|
+
else
|
|
86
|
+
new(attributes, &block)
|
|
87
|
+
end
|
|
335
88
|
end
|
|
336
89
|
|
|
337
90
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
|
@@ -426,56 +179,63 @@ module ActiveRecord
|
|
|
426
179
|
end
|
|
427
180
|
end
|
|
428
181
|
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
182
|
+
# Accepts a list of attribute names to be used in the WHERE clause
|
|
183
|
+
# of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for +#first+ and +#last+ finder methods.
|
|
184
|
+
#
|
|
185
|
+
# class Developer < ActiveRecord::Base
|
|
186
|
+
# query_constraints :company_id, :id
|
|
187
|
+
# end
|
|
432
188
|
#
|
|
433
|
-
#
|
|
434
|
-
#
|
|
189
|
+
# developer = Developer.first
|
|
190
|
+
# # SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
|
|
191
|
+
# developer.inspect # => #<Developer id: 1, company_id: 1, ...>
|
|
435
192
|
#
|
|
436
|
-
#
|
|
193
|
+
# developer.update!(name: "Nikita")
|
|
194
|
+
# # UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
|
437
195
|
#
|
|
438
|
-
#
|
|
196
|
+
# # It is possible to update an attribute used in the query_constraints clause:
|
|
197
|
+
# developer.update!(company_id: 2)
|
|
198
|
+
# # UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
|
439
199
|
#
|
|
440
|
-
#
|
|
200
|
+
# developer.name = "Bob"
|
|
201
|
+
# developer.save!
|
|
202
|
+
# # UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
|
441
203
|
#
|
|
442
|
-
#
|
|
443
|
-
#
|
|
204
|
+
# developer.destroy!
|
|
205
|
+
# # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
|
444
206
|
#
|
|
445
|
-
#
|
|
446
|
-
#
|
|
447
|
-
#
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
207
|
+
# developer.delete
|
|
208
|
+
# # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
|
209
|
+
#
|
|
210
|
+
# developer.reload
|
|
211
|
+
# # SELECT "developers".* FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1 LIMIT 1
|
|
212
|
+
def query_constraints(*columns_list)
|
|
213
|
+
raise ArgumentError, "You must specify at least one column to be used in querying" if columns_list.empty?
|
|
214
|
+
|
|
215
|
+
@query_constraints_list = columns_list.map(&:to_s)
|
|
216
|
+
@has_query_constraints = @query_constraints_list
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def has_query_constraints? # :nodoc:
|
|
220
|
+
@has_query_constraints
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def query_constraints_list # :nodoc:
|
|
224
|
+
@query_constraints_list ||= if base_class? || primary_key != base_class.primary_key
|
|
225
|
+
primary_key if primary_key.is_a?(Array)
|
|
451
226
|
else
|
|
452
|
-
|
|
227
|
+
base_class.query_constraints_list
|
|
453
228
|
end
|
|
454
229
|
end
|
|
455
230
|
|
|
456
|
-
#
|
|
457
|
-
#
|
|
458
|
-
#
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
# You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
|
|
462
|
-
#
|
|
463
|
-
# Note: Although it is often much faster than the alternative, #destroy,
|
|
464
|
-
# skipping callbacks might bypass business logic in your application
|
|
465
|
-
# that ensures referential integrity or performs other essential jobs.
|
|
466
|
-
#
|
|
467
|
-
# ==== Examples
|
|
468
|
-
#
|
|
469
|
-
# # Delete a single row
|
|
470
|
-
# Todo.delete(1)
|
|
471
|
-
#
|
|
472
|
-
# # Delete multiple rows
|
|
473
|
-
# Todo.delete([2,3,4])
|
|
474
|
-
def delete(id_or_array)
|
|
475
|
-
delete_by(primary_key => id_or_array)
|
|
231
|
+
# Returns an array of column names to be used in queries. The source of column
|
|
232
|
+
# names is derived from +query_constraints_list+ or +primary_key+. This method
|
|
233
|
+
# is for internal use when the primary key is to be treated as an array.
|
|
234
|
+
def composite_query_constraints_list # :nodoc:
|
|
235
|
+
@composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
|
|
476
236
|
end
|
|
477
237
|
|
|
478
|
-
def _insert_record(values) # :nodoc:
|
|
238
|
+
def _insert_record(connection, values, returning) # :nodoc:
|
|
479
239
|
primary_key = self.primary_key
|
|
480
240
|
primary_key_value = nil
|
|
481
241
|
|
|
@@ -488,13 +248,18 @@ module ActiveRecord
|
|
|
488
248
|
|
|
489
249
|
im = Arel::InsertManager.new(arel_table)
|
|
490
250
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
251
|
+
with_connection do |c|
|
|
252
|
+
if values.empty?
|
|
253
|
+
im.insert(connection.empty_insert_statement_value(primary_key))
|
|
254
|
+
else
|
|
255
|
+
im.insert(values.transform_keys { |name| arel_table[name] })
|
|
256
|
+
end
|
|
496
257
|
|
|
497
|
-
|
|
258
|
+
connection.insert(
|
|
259
|
+
im, "#{self} Create", primary_key || false, primary_key_value,
|
|
260
|
+
returning: returning
|
|
261
|
+
)
|
|
262
|
+
end
|
|
498
263
|
end
|
|
499
264
|
|
|
500
265
|
def _update_record(values, constraints) # :nodoc:
|
|
@@ -511,7 +276,9 @@ module ActiveRecord
|
|
|
511
276
|
um.set(values.transform_keys { |name| arel_table[name] })
|
|
512
277
|
um.wheres = constraints
|
|
513
278
|
|
|
514
|
-
|
|
279
|
+
with_connection do |c|
|
|
280
|
+
c.update(um, "#{self} Update")
|
|
281
|
+
end
|
|
515
282
|
end
|
|
516
283
|
|
|
517
284
|
def _delete_record(constraints) # :nodoc:
|
|
@@ -527,10 +294,20 @@ module ActiveRecord
|
|
|
527
294
|
dm = Arel::DeleteManager.new(arel_table)
|
|
528
295
|
dm.wheres = constraints
|
|
529
296
|
|
|
530
|
-
|
|
297
|
+
with_connection do |c|
|
|
298
|
+
c.delete(dm, "#{self} Destroy")
|
|
299
|
+
end
|
|
531
300
|
end
|
|
532
301
|
|
|
533
302
|
private
|
|
303
|
+
def inherited(subclass)
|
|
304
|
+
super
|
|
305
|
+
subclass.class_eval do
|
|
306
|
+
@_query_constraints_list = nil
|
|
307
|
+
@has_query_constraints = false
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
534
311
|
# Given a class, an attributes hash, +instantiate_instance_of+ returns a
|
|
535
312
|
# new instance of the class. Accepts only keys as strings.
|
|
536
313
|
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
|
|
@@ -565,7 +342,7 @@ module ActiveRecord
|
|
|
565
342
|
end
|
|
566
343
|
|
|
567
344
|
# Returns true if this object was just created -- that is, prior to the last
|
|
568
|
-
#
|
|
345
|
+
# update or delete, the object didn't exist in the database and new_record? would have
|
|
569
346
|
# returned true.
|
|
570
347
|
def previously_new_record?
|
|
571
348
|
@previously_new_record
|
|
@@ -664,6 +441,7 @@ module ActiveRecord
|
|
|
664
441
|
def delete
|
|
665
442
|
_delete_row if persisted?
|
|
666
443
|
@destroyed = true
|
|
444
|
+
@previously_new_record = false
|
|
667
445
|
freeze
|
|
668
446
|
end
|
|
669
447
|
|
|
@@ -677,12 +455,9 @@ module ActiveRecord
|
|
|
677
455
|
def destroy
|
|
678
456
|
_raise_readonly_record_error if readonly?
|
|
679
457
|
destroy_associations
|
|
680
|
-
@_trigger_destroy_callback
|
|
681
|
-
destroy_row > 0
|
|
682
|
-
else
|
|
683
|
-
true
|
|
684
|
-
end
|
|
458
|
+
@_trigger_destroy_callback ||= persisted? && destroy_row > 0
|
|
685
459
|
@destroyed = true
|
|
460
|
+
@previously_new_record = false
|
|
686
461
|
freeze
|
|
687
462
|
end
|
|
688
463
|
|
|
@@ -708,11 +483,14 @@ module ActiveRecord
|
|
|
708
483
|
# Note: The new instance will share a link to the same attributes as the original class.
|
|
709
484
|
# Therefore the STI column value will still be the same.
|
|
710
485
|
# Any change to the attributes on either instance will affect both instances.
|
|
486
|
+
# This includes any attribute initialization done by the new instance.
|
|
487
|
+
#
|
|
711
488
|
# If you want to change the STI column as well, use #becomes! instead.
|
|
712
489
|
def becomes(klass)
|
|
713
490
|
became = klass.allocate
|
|
714
491
|
|
|
715
492
|
became.send(:initialize) do |becoming|
|
|
493
|
+
@attributes.reverse_merge!(becoming.instance_variable_get(:@attributes))
|
|
716
494
|
becoming.instance_variable_set(:@attributes, @attributes)
|
|
717
495
|
becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
|
|
718
496
|
becoming.instance_variable_set(:@new_record, new_record?)
|
|
@@ -747,7 +525,7 @@ module ActiveRecord
|
|
|
747
525
|
# * updated_at/updated_on column is updated if that column is available.
|
|
748
526
|
# * Updates all the attributes that are dirty in this object.
|
|
749
527
|
#
|
|
750
|
-
# This method raises an ActiveRecord::ActiveRecordError
|
|
528
|
+
# This method raises an ActiveRecord::ActiveRecordError if the
|
|
751
529
|
# attribute is marked as readonly.
|
|
752
530
|
#
|
|
753
531
|
# Also see #update_column.
|
|
@@ -759,6 +537,28 @@ module ActiveRecord
|
|
|
759
537
|
save(validate: false)
|
|
760
538
|
end
|
|
761
539
|
|
|
540
|
+
# Updates a single attribute and saves the record.
|
|
541
|
+
# This is especially useful for boolean flags on existing records. Also note that
|
|
542
|
+
#
|
|
543
|
+
# * Validation is skipped.
|
|
544
|
+
# * \Callbacks are invoked.
|
|
545
|
+
# * updated_at/updated_on column is updated if that column is available.
|
|
546
|
+
# * Updates all the attributes that are dirty in this object.
|
|
547
|
+
#
|
|
548
|
+
# This method raises an ActiveRecord::ActiveRecordError if the
|
|
549
|
+
# attribute is marked as readonly.
|
|
550
|
+
#
|
|
551
|
+
# If any of the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
|
|
552
|
+
# and #update_attribute! raises ActiveRecord::RecordNotSaved. See
|
|
553
|
+
# ActiveRecord::Callbacks for further details.
|
|
554
|
+
def update_attribute!(name, value)
|
|
555
|
+
name = name.to_s
|
|
556
|
+
verify_readonly_attribute(name)
|
|
557
|
+
public_send("#{name}=", value)
|
|
558
|
+
|
|
559
|
+
save!(validate: false)
|
|
560
|
+
end
|
|
561
|
+
|
|
762
562
|
# Updates the attributes of the model from the passed-in hash and saves the
|
|
763
563
|
# record, all wrapped in a transaction. If the object is invalid, the saving
|
|
764
564
|
# will fail and false will be returned.
|
|
@@ -806,6 +606,7 @@ module ActiveRecord
|
|
|
806
606
|
def update_columns(attributes)
|
|
807
607
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
|
808
608
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
|
609
|
+
_raise_readonly_record_error if readonly?
|
|
809
610
|
|
|
810
611
|
attributes = attributes.transform_keys do |key|
|
|
811
612
|
name = key.to_s
|
|
@@ -813,7 +614,7 @@ module ActiveRecord
|
|
|
813
614
|
verify_readonly_attribute(name) || name
|
|
814
615
|
end
|
|
815
616
|
|
|
816
|
-
update_constraints =
|
|
617
|
+
update_constraints = _query_constraints_hash
|
|
817
618
|
attributes = attributes.each_with_object({}) do |(k, v), h|
|
|
818
619
|
h[k] = @attributes.write_cast_value(k, v)
|
|
819
620
|
clear_attribute_change(k)
|
|
@@ -941,15 +742,16 @@ module ActiveRecord
|
|
|
941
742
|
# end
|
|
942
743
|
#
|
|
943
744
|
def reload(options = nil)
|
|
944
|
-
self.class.
|
|
745
|
+
self.class.connection_pool.clear_query_cache
|
|
945
746
|
|
|
946
747
|
fresh_object = if apply_scoping?(options)
|
|
947
|
-
_find_record(options)
|
|
748
|
+
_find_record((options || {}).merge(all_queries: true))
|
|
948
749
|
else
|
|
949
750
|
self.class.unscoped { _find_record(options) }
|
|
950
751
|
end
|
|
951
752
|
|
|
952
753
|
@association_cache = fresh_object.instance_variable_get(:@association_cache)
|
|
754
|
+
@association_cache.each_value { |association| association.owner = self }
|
|
953
755
|
@attributes = fresh_object.instance_variable_get(:@attributes)
|
|
954
756
|
@new_record = false
|
|
955
757
|
@previously_new_record = false
|
|
@@ -992,12 +794,15 @@ module ActiveRecord
|
|
|
992
794
|
#
|
|
993
795
|
def touch(*names, time: nil)
|
|
994
796
|
_raise_record_not_touched_error unless persisted?
|
|
797
|
+
_raise_readonly_record_error if readonly?
|
|
995
798
|
|
|
996
799
|
attribute_names = timestamp_attributes_for_update_in_model
|
|
997
|
-
attribute_names
|
|
800
|
+
attribute_names = (attribute_names | names).map! do |name|
|
|
998
801
|
name = name.to_s
|
|
999
|
-
self.class.attribute_aliases[name] || name
|
|
1000
|
-
|
|
802
|
+
name = self.class.attribute_aliases[name] || name
|
|
803
|
+
verify_readonly_attribute(name)
|
|
804
|
+
name
|
|
805
|
+
end
|
|
1001
806
|
|
|
1002
807
|
unless attribute_names.empty?
|
|
1003
808
|
affected_rows = _touch_row(attribute_names, time)
|
|
@@ -1008,6 +813,12 @@ module ActiveRecord
|
|
|
1008
813
|
end
|
|
1009
814
|
|
|
1010
815
|
private
|
|
816
|
+
def init_internals
|
|
817
|
+
super
|
|
818
|
+
@_trigger_destroy_callback = @_trigger_update_callback = nil
|
|
819
|
+
@previously_new_record = false
|
|
820
|
+
end
|
|
821
|
+
|
|
1011
822
|
def strict_loaded_associations
|
|
1012
823
|
@association_cache.find_all do |_, assoc|
|
|
1013
824
|
assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
|
|
@@ -1015,10 +826,23 @@ module ActiveRecord
|
|
|
1015
826
|
end
|
|
1016
827
|
|
|
1017
828
|
def _find_record(options)
|
|
829
|
+
all_queries = options ? options[:all_queries] : nil
|
|
830
|
+
base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
|
|
831
|
+
|
|
1018
832
|
if options && options[:lock]
|
|
1019
|
-
|
|
833
|
+
base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
|
|
834
|
+
else
|
|
835
|
+
base.find_by!(_in_memory_query_constraints_hash)
|
|
836
|
+
end
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
def _in_memory_query_constraints_hash
|
|
840
|
+
if self.class.query_constraints_list.nil?
|
|
841
|
+
{ @primary_key => id }
|
|
1020
842
|
else
|
|
1021
|
-
self.class.
|
|
843
|
+
self.class.query_constraints_list.index_with do |column_name|
|
|
844
|
+
attribute(column_name)
|
|
845
|
+
end
|
|
1022
846
|
end
|
|
1023
847
|
end
|
|
1024
848
|
|
|
@@ -1027,8 +851,14 @@ module ActiveRecord
|
|
|
1027
851
|
(self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
|
|
1028
852
|
end
|
|
1029
853
|
|
|
1030
|
-
def
|
|
1031
|
-
|
|
854
|
+
def _query_constraints_hash
|
|
855
|
+
if self.class.query_constraints_list.nil?
|
|
856
|
+
{ @primary_key => id_in_database }
|
|
857
|
+
else
|
|
858
|
+
self.class.query_constraints_list.index_with do |column_name|
|
|
859
|
+
attribute_in_database(column_name)
|
|
860
|
+
end
|
|
861
|
+
end
|
|
1032
862
|
end
|
|
1033
863
|
|
|
1034
864
|
# A hook to be overridden by association modules.
|
|
@@ -1040,7 +870,7 @@ module ActiveRecord
|
|
|
1040
870
|
end
|
|
1041
871
|
|
|
1042
872
|
def _delete_row
|
|
1043
|
-
self.class._delete_record(
|
|
873
|
+
self.class._delete_record(_query_constraints_hash)
|
|
1044
874
|
end
|
|
1045
875
|
|
|
1046
876
|
def _touch_row(attribute_names, time)
|
|
@@ -1056,7 +886,7 @@ module ActiveRecord
|
|
|
1056
886
|
def _update_row(attribute_names, attempted_action = "update")
|
|
1057
887
|
self.class._update_record(
|
|
1058
888
|
attributes_with_values(attribute_names),
|
|
1059
|
-
|
|
889
|
+
_query_constraints_hash
|
|
1060
890
|
)
|
|
1061
891
|
end
|
|
1062
892
|
|
|
@@ -1092,11 +922,19 @@ module ActiveRecord
|
|
|
1092
922
|
def _create_record(attribute_names = self.attribute_names)
|
|
1093
923
|
attribute_names = attributes_for_create(attribute_names)
|
|
1094
924
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
)
|
|
925
|
+
self.class.with_connection do |connection|
|
|
926
|
+
returning_columns = self.class._returning_columns_for_insert(connection)
|
|
1098
927
|
|
|
1099
|
-
|
|
928
|
+
returning_values = self.class._insert_record(
|
|
929
|
+
connection,
|
|
930
|
+
attributes_with_values(attribute_names),
|
|
931
|
+
returning_columns
|
|
932
|
+
)
|
|
933
|
+
|
|
934
|
+
returning_columns.zip(returning_values).each do |column, value|
|
|
935
|
+
_write_attribute(column, value) if !_read_attribute(column)
|
|
936
|
+
end if returning_values
|
|
937
|
+
end
|
|
1100
938
|
|
|
1101
939
|
@new_record = false
|
|
1102
940
|
@previously_new_record = true
|
|
@@ -1113,7 +951,7 @@ module ActiveRecord
|
|
|
1113
951
|
def _raise_record_not_destroyed
|
|
1114
952
|
@_association_destroy_exception ||= nil
|
|
1115
953
|
key = self.class.primary_key
|
|
1116
|
-
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{
|
|
954
|
+
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
|
|
1117
955
|
ensure
|
|
1118
956
|
@_association_destroy_exception = nil
|
|
1119
957
|
end
|
|
@@ -1128,11 +966,5 @@ module ActiveRecord
|
|
|
1128
966
|
persisted?, new_record?, or destroyed? before touching.
|
|
1129
967
|
MSG
|
|
1130
968
|
end
|
|
1131
|
-
|
|
1132
|
-
# The name of the method used to touch a +belongs_to+ association when the
|
|
1133
|
-
# +:touch+ option is used.
|
|
1134
|
-
def belongs_to_touch_method
|
|
1135
|
-
:touch
|
|
1136
|
-
end
|
|
1137
969
|
end
|
|
1138
970
|
end
|