activerecord 7.1.5.2 → 8.1.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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- 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 +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +268 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +250 -315
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
|
@@ -87,282 +87,6 @@ module ActiveRecord
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
# Inserts a single record into the database in a single SQL INSERT
|
|
91
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
92
|
-
# Active Record callbacks or validations. Though passed values
|
|
93
|
-
# go through Active Record's type casting and serialization.
|
|
94
|
-
#
|
|
95
|
-
# See #insert_all for documentation.
|
|
96
|
-
def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
|
|
97
|
-
insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Inserts multiple records into the database in a single SQL INSERT
|
|
101
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
102
|
-
# Active Record callbacks or validations. Though passed values
|
|
103
|
-
# go through Active Record's type casting and serialization.
|
|
104
|
-
#
|
|
105
|
-
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
|
106
|
-
# the attributes for a single row and must have the same keys.
|
|
107
|
-
#
|
|
108
|
-
# Rows are considered to be unique by every unique index on the table. Any
|
|
109
|
-
# duplicate rows are skipped.
|
|
110
|
-
# Override with <tt>:unique_by</tt> (see below).
|
|
111
|
-
#
|
|
112
|
-
# Returns an ActiveRecord::Result with its contents based on
|
|
113
|
-
# <tt>:returning</tt> (see below).
|
|
114
|
-
#
|
|
115
|
-
# ==== Options
|
|
116
|
-
#
|
|
117
|
-
# [:returning]
|
|
118
|
-
# (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
|
|
119
|
-
# inserted records, which by default is the primary key.
|
|
120
|
-
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
121
|
-
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
122
|
-
# clause entirely.
|
|
123
|
-
#
|
|
124
|
-
# You can also pass an SQL string if you need more control on the return values
|
|
125
|
-
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
|
126
|
-
#
|
|
127
|
-
# [:unique_by]
|
|
128
|
-
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
|
129
|
-
# by every unique index on the table. Any duplicate rows are skipped.
|
|
130
|
-
#
|
|
131
|
-
# To skip rows according to just one unique index pass <tt>:unique_by</tt>.
|
|
132
|
-
#
|
|
133
|
-
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
|
134
|
-
# row has an existing id, or is not unique by another unique index,
|
|
135
|
-
# ActiveRecord::RecordNotUnique is raised.
|
|
136
|
-
#
|
|
137
|
-
# Unique indexes can be identified by columns or name:
|
|
138
|
-
#
|
|
139
|
-
# unique_by: :isbn
|
|
140
|
-
# unique_by: %i[ author_id name ]
|
|
141
|
-
# unique_by: :index_books_on_isbn
|
|
142
|
-
#
|
|
143
|
-
# [:record_timestamps]
|
|
144
|
-
# By default, automatic setting of timestamp columns is controlled by
|
|
145
|
-
# the model's <tt>record_timestamps</tt> config, matching typical
|
|
146
|
-
# behavior.
|
|
147
|
-
#
|
|
148
|
-
# To override this and force automatic setting of timestamp columns one
|
|
149
|
-
# way or the other, pass <tt>:record_timestamps</tt>:
|
|
150
|
-
#
|
|
151
|
-
# record_timestamps: true # Always set timestamps automatically
|
|
152
|
-
# record_timestamps: false # Never set timestamps automatically
|
|
153
|
-
#
|
|
154
|
-
# Because it relies on the index information from the database
|
|
155
|
-
# <tt>:unique_by</tt> is recommended to be paired with
|
|
156
|
-
# Active Record's schema_cache.
|
|
157
|
-
#
|
|
158
|
-
# ==== Example
|
|
159
|
-
#
|
|
160
|
-
# # Insert records and skip inserting any duplicates.
|
|
161
|
-
# # Here "Eloquent Ruby" is skipped because its id is not unique.
|
|
162
|
-
#
|
|
163
|
-
# Book.insert_all([
|
|
164
|
-
# { id: 1, title: "Rework", author: "David" },
|
|
165
|
-
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
|
166
|
-
# ])
|
|
167
|
-
#
|
|
168
|
-
# # insert_all works on chained scopes, and you can use create_with
|
|
169
|
-
# # to set default attributes for all inserted records.
|
|
170
|
-
#
|
|
171
|
-
# author.books.create_with(created_at: Time.now).insert_all([
|
|
172
|
-
# { id: 1, title: "Rework" },
|
|
173
|
-
# { id: 2, title: "Eloquent Ruby" }
|
|
174
|
-
# ])
|
|
175
|
-
def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
|
|
176
|
-
InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# Inserts a single record into the database in a single SQL INSERT
|
|
180
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
181
|
-
# Active Record callbacks or validations. Though passed values
|
|
182
|
-
# go through Active Record's type casting and serialization.
|
|
183
|
-
#
|
|
184
|
-
# See #insert_all! for more.
|
|
185
|
-
def insert!(attributes, returning: nil, record_timestamps: nil)
|
|
186
|
-
insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# Inserts multiple records into the database in a single SQL INSERT
|
|
190
|
-
# statement. It does not instantiate any models nor does it trigger
|
|
191
|
-
# Active Record callbacks or validations. Though passed values
|
|
192
|
-
# go through Active Record's type casting and serialization.
|
|
193
|
-
#
|
|
194
|
-
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
|
195
|
-
# the attributes for a single row and must have the same keys.
|
|
196
|
-
#
|
|
197
|
-
# Raises ActiveRecord::RecordNotUnique if any rows violate a
|
|
198
|
-
# unique index on the table. In that case, no rows are inserted.
|
|
199
|
-
#
|
|
200
|
-
# To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
|
|
201
|
-
#
|
|
202
|
-
# Returns an ActiveRecord::Result with its contents based on
|
|
203
|
-
# <tt>:returning</tt> (see below).
|
|
204
|
-
#
|
|
205
|
-
# ==== Options
|
|
206
|
-
#
|
|
207
|
-
# [:returning]
|
|
208
|
-
# (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
|
|
209
|
-
# inserted records, which by default is the primary key.
|
|
210
|
-
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
211
|
-
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
212
|
-
# clause entirely.
|
|
213
|
-
#
|
|
214
|
-
# You can also pass an SQL string if you need more control on the return values
|
|
215
|
-
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
|
216
|
-
#
|
|
217
|
-
# [:record_timestamps]
|
|
218
|
-
# By default, automatic setting of timestamp columns is controlled by
|
|
219
|
-
# the model's <tt>record_timestamps</tt> config, matching typical
|
|
220
|
-
# behavior.
|
|
221
|
-
#
|
|
222
|
-
# To override this and force automatic setting of timestamp columns one
|
|
223
|
-
# way or the other, pass <tt>:record_timestamps</tt>:
|
|
224
|
-
#
|
|
225
|
-
# record_timestamps: true # Always set timestamps automatically
|
|
226
|
-
# record_timestamps: false # Never set timestamps automatically
|
|
227
|
-
#
|
|
228
|
-
# ==== Examples
|
|
229
|
-
#
|
|
230
|
-
# # Insert multiple records
|
|
231
|
-
# Book.insert_all!([
|
|
232
|
-
# { title: "Rework", author: "David" },
|
|
233
|
-
# { title: "Eloquent Ruby", author: "Russ" }
|
|
234
|
-
# ])
|
|
235
|
-
#
|
|
236
|
-
# # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
|
|
237
|
-
# # does not have a unique id.
|
|
238
|
-
# Book.insert_all!([
|
|
239
|
-
# { id: 1, title: "Rework", author: "David" },
|
|
240
|
-
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
|
241
|
-
# ])
|
|
242
|
-
def insert_all!(attributes, returning: nil, record_timestamps: nil)
|
|
243
|
-
InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
# Updates or inserts (upserts) a single record into the database in a
|
|
247
|
-
# single SQL INSERT statement. It does not instantiate any models nor does
|
|
248
|
-
# it trigger Active Record callbacks or validations. Though passed values
|
|
249
|
-
# go through Active Record's type casting and serialization.
|
|
250
|
-
#
|
|
251
|
-
# See #upsert_all for documentation.
|
|
252
|
-
def upsert(attributes, **kwargs)
|
|
253
|
-
upsert_all([ attributes ], **kwargs)
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
# Updates or inserts (upserts) multiple records into the database in a
|
|
257
|
-
# single SQL INSERT statement. It does not instantiate any models nor does
|
|
258
|
-
# it trigger Active Record callbacks or validations. Though passed values
|
|
259
|
-
# go through Active Record's type casting and serialization.
|
|
260
|
-
#
|
|
261
|
-
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
|
262
|
-
# the attributes for a single row and must have the same keys.
|
|
263
|
-
#
|
|
264
|
-
# Returns an ActiveRecord::Result with its contents based on
|
|
265
|
-
# <tt>:returning</tt> (see below).
|
|
266
|
-
#
|
|
267
|
-
# By default, +upsert_all+ will update all the columns that can be updated when
|
|
268
|
-
# there is a conflict. These are all the columns except primary keys, read-only
|
|
269
|
-
# columns, and columns covered by the optional +unique_by+.
|
|
270
|
-
#
|
|
271
|
-
# ==== Options
|
|
272
|
-
#
|
|
273
|
-
# [:returning]
|
|
274
|
-
# (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
|
|
275
|
-
# inserted records, which by default is the primary key.
|
|
276
|
-
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
277
|
-
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
278
|
-
# clause entirely.
|
|
279
|
-
#
|
|
280
|
-
# You can also pass an SQL string if you need more control on the return values
|
|
281
|
-
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
|
282
|
-
#
|
|
283
|
-
# [:unique_by]
|
|
284
|
-
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
|
285
|
-
# by every unique index on the table. Any duplicate rows are skipped.
|
|
286
|
-
#
|
|
287
|
-
# To skip rows according to just one unique index pass <tt>:unique_by</tt>.
|
|
288
|
-
#
|
|
289
|
-
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
|
290
|
-
# row has an existing id, or is not unique by another unique index,
|
|
291
|
-
# ActiveRecord::RecordNotUnique is raised.
|
|
292
|
-
#
|
|
293
|
-
# Unique indexes can be identified by columns or name:
|
|
294
|
-
#
|
|
295
|
-
# unique_by: :isbn
|
|
296
|
-
# unique_by: %i[ author_id name ]
|
|
297
|
-
# unique_by: :index_books_on_isbn
|
|
298
|
-
#
|
|
299
|
-
# Because it relies on the index information from the database
|
|
300
|
-
# <tt>:unique_by</tt> is recommended to be paired with
|
|
301
|
-
# Active Record's schema_cache.
|
|
302
|
-
#
|
|
303
|
-
# [:on_duplicate]
|
|
304
|
-
# Configure the SQL update sentence that will be used in case of conflict.
|
|
305
|
-
#
|
|
306
|
-
# NOTE: If you use this option you must provide all the columns you want to update
|
|
307
|
-
# by yourself.
|
|
308
|
-
#
|
|
309
|
-
# Example:
|
|
310
|
-
#
|
|
311
|
-
# Commodity.upsert_all(
|
|
312
|
-
# [
|
|
313
|
-
# { id: 2, name: "Copper", price: 4.84 },
|
|
314
|
-
# { id: 4, name: "Gold", price: 1380.87 },
|
|
315
|
-
# { id: 6, name: "Aluminium", price: 0.35 }
|
|
316
|
-
# ],
|
|
317
|
-
# on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
|
|
318
|
-
# )
|
|
319
|
-
#
|
|
320
|
-
# See the related +:update_only+ option. Both options can't be used at the same time.
|
|
321
|
-
#
|
|
322
|
-
# [:update_only]
|
|
323
|
-
# Provide a list of column names that will be updated in case of conflict. If not provided,
|
|
324
|
-
# +upsert_all+ will update all the columns that can be updated. These are all the columns
|
|
325
|
-
# except primary keys, read-only columns, and columns covered by the optional +unique_by+
|
|
326
|
-
#
|
|
327
|
-
# Example:
|
|
328
|
-
#
|
|
329
|
-
# Commodity.upsert_all(
|
|
330
|
-
# [
|
|
331
|
-
# { id: 2, name: "Copper", price: 4.84 },
|
|
332
|
-
# { id: 4, name: "Gold", price: 1380.87 },
|
|
333
|
-
# { id: 6, name: "Aluminium", price: 0.35 }
|
|
334
|
-
# ],
|
|
335
|
-
# update_only: [:price] # Only prices will be updated
|
|
336
|
-
# )
|
|
337
|
-
#
|
|
338
|
-
# See the related +:on_duplicate+ option. Both options can't be used at the same time.
|
|
339
|
-
#
|
|
340
|
-
# [:record_timestamps]
|
|
341
|
-
# By default, automatic setting of timestamp columns is controlled by
|
|
342
|
-
# the model's <tt>record_timestamps</tt> config, matching typical
|
|
343
|
-
# behavior.
|
|
344
|
-
#
|
|
345
|
-
# To override this and force automatic setting of timestamp columns one
|
|
346
|
-
# way or the other, pass <tt>:record_timestamps</tt>:
|
|
347
|
-
#
|
|
348
|
-
# record_timestamps: true # Always set timestamps automatically
|
|
349
|
-
# record_timestamps: false # Never set timestamps automatically
|
|
350
|
-
#
|
|
351
|
-
# ==== Examples
|
|
352
|
-
#
|
|
353
|
-
# # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
|
|
354
|
-
# # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
|
|
355
|
-
#
|
|
356
|
-
# Book.upsert_all([
|
|
357
|
-
# { title: "Rework", author: "David", isbn: "1" },
|
|
358
|
-
# { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
|
|
359
|
-
# ], unique_by: :isbn)
|
|
360
|
-
#
|
|
361
|
-
# Book.find_by(isbn: "1").title # => "Eloquent Ruby"
|
|
362
|
-
def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
|
|
363
|
-
InsertAll.new(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
|
|
364
|
-
end
|
|
365
|
-
|
|
366
90
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
|
367
91
|
# the appropriate class. Accepts only keys as strings.
|
|
368
92
|
#
|
|
@@ -511,62 +235,7 @@ module ActiveRecord
|
|
|
511
235
|
@composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
|
|
512
236
|
end
|
|
513
237
|
|
|
514
|
-
|
|
515
|
-
# therefore all callbacks and filters are fired off before the object is deleted. This method is
|
|
516
|
-
# less efficient than #delete but allows cleanup methods and other actions to be run.
|
|
517
|
-
#
|
|
518
|
-
# This essentially finds the object (or multiple objects) with the given id, creates a new object
|
|
519
|
-
# from the attributes, and then calls destroy on it.
|
|
520
|
-
#
|
|
521
|
-
# ==== Parameters
|
|
522
|
-
#
|
|
523
|
-
# * +id+ - This should be the id or an array of ids to be destroyed.
|
|
524
|
-
#
|
|
525
|
-
# ==== Examples
|
|
526
|
-
#
|
|
527
|
-
# # Destroy a single object
|
|
528
|
-
# Todo.destroy(1)
|
|
529
|
-
#
|
|
530
|
-
# # Destroy multiple objects
|
|
531
|
-
# todos = [1,2,3]
|
|
532
|
-
# Todo.destroy(todos)
|
|
533
|
-
def destroy(id)
|
|
534
|
-
multiple_ids = if composite_primary_key?
|
|
535
|
-
id.first.is_a?(Array)
|
|
536
|
-
else
|
|
537
|
-
id.is_a?(Array)
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
if multiple_ids
|
|
541
|
-
find(id).each(&:destroy)
|
|
542
|
-
else
|
|
543
|
-
find(id).destroy
|
|
544
|
-
end
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
# Deletes the row with a primary key matching the +id+ argument, using an
|
|
548
|
-
# SQL +DELETE+ statement, and returns the number of rows deleted. Active
|
|
549
|
-
# Record objects are not instantiated, so the object's callbacks are not
|
|
550
|
-
# executed, including any <tt>:dependent</tt> association options.
|
|
551
|
-
#
|
|
552
|
-
# You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
|
|
553
|
-
#
|
|
554
|
-
# Note: Although it is often much faster than the alternative, #destroy,
|
|
555
|
-
# skipping callbacks might bypass business logic in your application
|
|
556
|
-
# that ensures referential integrity or performs other essential jobs.
|
|
557
|
-
#
|
|
558
|
-
# ==== Examples
|
|
559
|
-
#
|
|
560
|
-
# # Delete a single row
|
|
561
|
-
# Todo.delete(1)
|
|
562
|
-
#
|
|
563
|
-
# # Delete multiple rows
|
|
564
|
-
# Todo.delete([2,3,4])
|
|
565
|
-
def delete(id_or_array)
|
|
566
|
-
delete_by(primary_key => id_or_array)
|
|
567
|
-
end
|
|
568
|
-
|
|
569
|
-
def _insert_record(values, returning) # :nodoc:
|
|
238
|
+
def _insert_record(connection, values, returning) # :nodoc:
|
|
570
239
|
primary_key = self.primary_key
|
|
571
240
|
primary_key_value = nil
|
|
572
241
|
|
|
@@ -605,7 +274,9 @@ module ActiveRecord
|
|
|
605
274
|
um.set(values.transform_keys { |name| arel_table[name] })
|
|
606
275
|
um.wheres = constraints
|
|
607
276
|
|
|
608
|
-
|
|
277
|
+
with_connection do |c|
|
|
278
|
+
c.update(um, "#{self} Update")
|
|
279
|
+
end
|
|
609
280
|
end
|
|
610
281
|
|
|
611
282
|
def _delete_record(constraints) # :nodoc:
|
|
@@ -621,7 +292,9 @@ module ActiveRecord
|
|
|
621
292
|
dm = Arel::DeleteManager.new(arel_table)
|
|
622
293
|
dm.wheres = constraints
|
|
623
294
|
|
|
624
|
-
|
|
295
|
+
with_connection do |c|
|
|
296
|
+
c.delete(dm, "#{self} Destroy")
|
|
297
|
+
end
|
|
625
298
|
end
|
|
626
299
|
|
|
627
300
|
private
|
|
@@ -819,6 +492,7 @@ module ActiveRecord
|
|
|
819
492
|
becoming.instance_variable_set(:@attributes, @attributes)
|
|
820
493
|
becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
|
|
821
494
|
becoming.instance_variable_set(:@new_record, new_record?)
|
|
495
|
+
becoming.instance_variable_set(:@previously_new_record, previously_new_record?)
|
|
822
496
|
becoming.instance_variable_set(:@destroyed, destroyed?)
|
|
823
497
|
becoming.errors.copy!(errors)
|
|
824
498
|
end
|
|
@@ -908,8 +582,8 @@ module ActiveRecord
|
|
|
908
582
|
end
|
|
909
583
|
|
|
910
584
|
# Equivalent to <code>update_columns(name => value)</code>.
|
|
911
|
-
def update_column(name, value)
|
|
912
|
-
update_columns(name => value)
|
|
585
|
+
def update_column(name, value, touch: nil)
|
|
586
|
+
update_columns(name => value, touch: touch)
|
|
913
587
|
end
|
|
914
588
|
|
|
915
589
|
# Updates the attributes directly in the database issuing an UPDATE SQL
|
|
@@ -923,11 +597,25 @@ module ActiveRecord
|
|
|
923
597
|
#
|
|
924
598
|
# * \Validations are skipped.
|
|
925
599
|
# * \Callbacks are skipped.
|
|
926
|
-
# * +updated_at+/+updated_on+ are
|
|
600
|
+
# * +updated_at+/+updated_on+ are updated if the +touch+ option is set to +true+.
|
|
927
601
|
# * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
|
|
928
602
|
#
|
|
929
603
|
# This method raises an ActiveRecord::ActiveRecordError when called on new
|
|
930
604
|
# objects, or when at least one of the attributes is marked as readonly.
|
|
605
|
+
#
|
|
606
|
+
# ==== Parameters
|
|
607
|
+
#
|
|
608
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
|
609
|
+
# * If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
|
|
610
|
+
#
|
|
611
|
+
# ==== Examples
|
|
612
|
+
#
|
|
613
|
+
# # Update a single attribute.
|
|
614
|
+
# user.update_columns(last_request_at: Time.current)
|
|
615
|
+
#
|
|
616
|
+
# # Update with touch option.
|
|
617
|
+
# user.update_columns(last_request_at: Time.current, touch: true)
|
|
618
|
+
|
|
931
619
|
def update_columns(attributes)
|
|
932
620
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
|
933
621
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
|
@@ -939,6 +627,15 @@ module ActiveRecord
|
|
|
939
627
|
verify_readonly_attribute(name) || name
|
|
940
628
|
end
|
|
941
629
|
|
|
630
|
+
touch = attributes.delete("touch")
|
|
631
|
+
if touch
|
|
632
|
+
names = touch if touch != true
|
|
633
|
+
names = Array.wrap(names)
|
|
634
|
+
options = names.extract_options!
|
|
635
|
+
touch_updates = self.class.touch_attributes_with_time(*names, **options)
|
|
636
|
+
attributes.with_defaults!(touch_updates) unless touch_updates.empty?
|
|
637
|
+
end
|
|
638
|
+
|
|
942
639
|
update_constraints = _query_constraints_hash
|
|
943
640
|
attributes = attributes.each_with_object({}) do |(k, v), h|
|
|
944
641
|
h[k] = @attributes.write_cast_value(k, v)
|
|
@@ -967,8 +664,15 @@ module ActiveRecord
|
|
|
967
664
|
# This means that any other modified attributes will still be dirty.
|
|
968
665
|
# Validations and callbacks are skipped. Supports the +touch+ option from
|
|
969
666
|
# +update_counters+, see that for more.
|
|
667
|
+
#
|
|
668
|
+
# This method raises an ActiveRecord::ActiveRecordError when called on new
|
|
669
|
+
# objects, or when at least one of the attributes is marked as readonly.
|
|
670
|
+
#
|
|
970
671
|
# Returns +self+.
|
|
971
672
|
def increment!(attribute, by = 1, touch: nil)
|
|
673
|
+
raise ActiveRecordError, "cannot update a new record" if new_record?
|
|
674
|
+
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
|
675
|
+
|
|
972
676
|
increment(attribute, by)
|
|
973
677
|
change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
|
|
974
678
|
self.class.update_counters(id, attribute => change, touch: touch)
|
|
@@ -1067,7 +771,7 @@ module ActiveRecord
|
|
|
1067
771
|
# end
|
|
1068
772
|
#
|
|
1069
773
|
def reload(options = nil)
|
|
1070
|
-
self.class.
|
|
774
|
+
self.class.connection_pool.clear_query_cache
|
|
1071
775
|
|
|
1072
776
|
fresh_object = if apply_scoping?(options)
|
|
1073
777
|
_find_record((options || {}).merge(all_queries: true))
|
|
@@ -1137,156 +841,159 @@ module ActiveRecord
|
|
|
1137
841
|
end
|
|
1138
842
|
end
|
|
1139
843
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
844
|
+
private
|
|
845
|
+
def init_internals
|
|
846
|
+
super
|
|
847
|
+
@_trigger_destroy_callback = @_trigger_update_callback = nil
|
|
848
|
+
@previously_new_record = false
|
|
849
|
+
end
|
|
1146
850
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
851
|
+
def strict_loaded_associations
|
|
852
|
+
@association_cache.find_all do |_, assoc|
|
|
853
|
+
assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
|
|
854
|
+
end.map(&:first)
|
|
855
|
+
end
|
|
1152
856
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
857
|
+
def _find_record(options)
|
|
858
|
+
all_queries = options ? options[:all_queries] : nil
|
|
859
|
+
base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
|
|
1156
860
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
861
|
+
if options && options[:lock]
|
|
862
|
+
base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
|
|
863
|
+
else
|
|
864
|
+
base.find_by!(_in_memory_query_constraints_hash)
|
|
865
|
+
end
|
|
1161
866
|
end
|
|
1162
|
-
end
|
|
1163
867
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
868
|
+
def _in_memory_query_constraints_hash
|
|
869
|
+
if self.class.query_constraints_list.nil?
|
|
870
|
+
{ @primary_key => id }
|
|
871
|
+
else
|
|
872
|
+
self.class.query_constraints_list.index_with do |column_name|
|
|
873
|
+
attribute(column_name)
|
|
874
|
+
end
|
|
1170
875
|
end
|
|
1171
876
|
end
|
|
1172
|
-
end
|
|
1173
877
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
878
|
+
def apply_scoping?(options)
|
|
879
|
+
!(options && options[:unscoped]) &&
|
|
880
|
+
(self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
|
|
881
|
+
end
|
|
1178
882
|
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
883
|
+
def _query_constraints_hash
|
|
884
|
+
if self.class.query_constraints_list.nil?
|
|
885
|
+
{ @primary_key => id_in_database }
|
|
886
|
+
else
|
|
887
|
+
self.class.query_constraints_list.index_with do |column_name|
|
|
888
|
+
attribute_in_database(column_name)
|
|
889
|
+
end
|
|
1185
890
|
end
|
|
1186
891
|
end
|
|
1187
|
-
end
|
|
1188
892
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
def destroy_row
|
|
1194
|
-
_delete_row
|
|
1195
|
-
end
|
|
1196
|
-
|
|
1197
|
-
def _delete_row
|
|
1198
|
-
self.class._delete_record(_query_constraints_hash)
|
|
1199
|
-
end
|
|
893
|
+
# A hook to be overridden by association modules.
|
|
894
|
+
def destroy_associations
|
|
895
|
+
end
|
|
1200
896
|
|
|
1201
|
-
|
|
1202
|
-
|
|
897
|
+
def destroy_row
|
|
898
|
+
_delete_row
|
|
899
|
+
end
|
|
1203
900
|
|
|
1204
|
-
|
|
1205
|
-
|
|
901
|
+
def _delete_row
|
|
902
|
+
self.class._delete_record(_query_constraints_hash)
|
|
1206
903
|
end
|
|
1207
904
|
|
|
1208
|
-
|
|
1209
|
-
|
|
905
|
+
def _touch_row(attribute_names, time)
|
|
906
|
+
time ||= current_time_from_proper_timezone
|
|
1210
907
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
_query_constraints_hash
|
|
1215
|
-
)
|
|
1216
|
-
end
|
|
908
|
+
attribute_names.each do |attr_name|
|
|
909
|
+
_write_attribute(attr_name, time)
|
|
910
|
+
end
|
|
1217
911
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
return false if destroyed?
|
|
1221
|
-
result = new_record? ? _create_record(&block) : _update_record(&block)
|
|
1222
|
-
result != false
|
|
1223
|
-
end
|
|
912
|
+
_update_row(attribute_names, "touch")
|
|
913
|
+
end
|
|
1224
914
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
915
|
+
def _update_row(attribute_names, attempted_action = "update")
|
|
916
|
+
self.class._update_record(
|
|
917
|
+
attributes_with_values(attribute_names),
|
|
918
|
+
_query_constraints_hash
|
|
919
|
+
)
|
|
920
|
+
end
|
|
1229
921
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
@_trigger_update_callback = affected_rows == 1
|
|
922
|
+
def create_or_update(**, &block)
|
|
923
|
+
_raise_readonly_record_error if readonly?
|
|
924
|
+
return false if destroyed?
|
|
925
|
+
result = new_record? ? _create_record(&block) : _update_record(&block)
|
|
926
|
+
result != false
|
|
1236
927
|
end
|
|
1237
928
|
|
|
1238
|
-
|
|
929
|
+
# Updates the associated record with values matching those of the instance attributes.
|
|
930
|
+
# Returns the number of affected rows.
|
|
931
|
+
def _update_record(attribute_names = self.attribute_names)
|
|
932
|
+
attribute_names = attributes_for_update(attribute_names)
|
|
1239
933
|
|
|
1240
|
-
|
|
934
|
+
if attribute_names.empty?
|
|
935
|
+
affected_rows = 0
|
|
936
|
+
@_trigger_update_callback = true
|
|
937
|
+
else
|
|
938
|
+
affected_rows = _update_row(attribute_names)
|
|
939
|
+
@_trigger_update_callback = affected_rows == 1
|
|
940
|
+
end
|
|
1241
941
|
|
|
1242
|
-
|
|
1243
|
-
end
|
|
942
|
+
@previously_new_record = false
|
|
1244
943
|
|
|
1245
|
-
|
|
1246
|
-
# and returns its id.
|
|
1247
|
-
def _create_record(attribute_names = self.attribute_names)
|
|
1248
|
-
attribute_names = attributes_for_create(attribute_names)
|
|
944
|
+
yield(self) if block_given?
|
|
1249
945
|
|
|
1250
|
-
|
|
946
|
+
affected_rows
|
|
947
|
+
end
|
|
1251
948
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
949
|
+
# Creates a record with values matching those of the instance attributes
|
|
950
|
+
# and returns its id.
|
|
951
|
+
def _create_record(attribute_names = self.attribute_names)
|
|
952
|
+
attribute_names = attributes_for_create(attribute_names)
|
|
1256
953
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
end if returning_values
|
|
954
|
+
self.class.with_connection do |connection|
|
|
955
|
+
returning_columns = self.class._returning_columns_for_insert(connection)
|
|
1260
956
|
|
|
1261
|
-
|
|
1262
|
-
|
|
957
|
+
returning_values = self.class._insert_record(
|
|
958
|
+
connection,
|
|
959
|
+
attributes_with_values(attribute_names),
|
|
960
|
+
returning_columns
|
|
961
|
+
)
|
|
1263
962
|
|
|
1264
|
-
|
|
963
|
+
returning_columns.zip(returning_values).each do |column, value|
|
|
964
|
+
_write_attribute(column, type_for_attribute(column).deserialize(value)) if !_read_attribute(column)
|
|
965
|
+
end if returning_values
|
|
966
|
+
end
|
|
1265
967
|
|
|
1266
|
-
|
|
1267
|
-
|
|
968
|
+
@new_record = false
|
|
969
|
+
@previously_new_record = true
|
|
1268
970
|
|
|
1269
|
-
|
|
1270
|
-
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
|
|
1271
|
-
end
|
|
971
|
+
yield(self) if block_given?
|
|
1272
972
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
key = self.class.primary_key
|
|
1276
|
-
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
|
|
1277
|
-
ensure
|
|
1278
|
-
@_association_destroy_exception = nil
|
|
1279
|
-
end
|
|
973
|
+
id
|
|
974
|
+
end
|
|
1280
975
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
976
|
+
def verify_readonly_attribute(name)
|
|
977
|
+
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
|
|
978
|
+
end
|
|
1284
979
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
980
|
+
def _raise_record_not_destroyed
|
|
981
|
+
@_association_destroy_exception ||= nil
|
|
982
|
+
key = self.class.primary_key
|
|
983
|
+
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
|
|
984
|
+
ensure
|
|
985
|
+
@_association_destroy_exception = nil
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
def _raise_readonly_record_error
|
|
989
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly"
|
|
990
|
+
end
|
|
991
|
+
|
|
992
|
+
def _raise_record_not_touched_error
|
|
993
|
+
raise ActiveRecordError, <<~MSG.squish
|
|
994
|
+
Cannot touch on a new or destroyed record object. Consider using
|
|
995
|
+
persisted?, new_record?, or destroyed? before touching.
|
|
996
|
+
MSG
|
|
997
|
+
end
|
|
1291
998
|
end
|
|
1292
999
|
end
|