activerecord 5.2.2.1 → 6.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +734 -508
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +16 -28
- data/lib/active_record/associations/collection_proxy.rb +19 -48
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +3 -10
- data/lib/active_record/associations/has_many_through_association.rb +20 -25
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +22 -8
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +137 -26
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +114 -130
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +26 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +135 -56
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +189 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +151 -198
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +7 -11
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -77
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +131 -143
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +104 -59
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +30 -16
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +91 -64
- data/lib/active_record/model_schema.rb +33 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +231 -25
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -22
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +67 -57
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +28 -28
- data/lib/active_record/relation/merger.rb +17 -23
- data/lib/active_record/relation/predicate_builder.rb +18 -15
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +17 -10
- data/lib/active_record/relation/query_methods.rb +247 -73
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +111 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -43,6 +43,13 @@ module ActiveRecord
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
# Returns +true+ if the class has +no_touching+ set, +false+ otherwise.
|
47
|
+
#
|
48
|
+
# Project.no_touching do
|
49
|
+
# Project.first.no_touching? # true
|
50
|
+
# Message.first.no_touching? # false
|
51
|
+
# end
|
52
|
+
#
|
46
53
|
def no_touching?
|
47
54
|
NoTouching.applied_to?(self.class)
|
48
55
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_record/insert_all"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
# = Active Record \Persistence
|
5
7
|
module Persistence
|
@@ -55,6 +57,192 @@ module ActiveRecord
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
60
|
+
# Inserts a single record into the database in a single SQL INSERT
|
61
|
+
# statement. It does not instantiate any models nor does it trigger
|
62
|
+
# Active Record callbacks or validations. Though passed values
|
63
|
+
# go through Active Record's type casting and serialization.
|
64
|
+
#
|
65
|
+
# See <tt>ActiveRecord::Persistence#insert_all</tt> for documentation.
|
66
|
+
def insert(attributes, returning: nil, unique_by: nil)
|
67
|
+
insert_all([ attributes ], returning: returning, unique_by: unique_by)
|
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
|
+
# [:unique_by]
|
95
|
+
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
96
|
+
# by every unique index on the table. Any duplicate rows are skipped.
|
97
|
+
#
|
98
|
+
# To skip rows according to just one unique index pass <tt>:unique_by</tt>.
|
99
|
+
#
|
100
|
+
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
101
|
+
# row has an existing id, or is not unique by another unique index,
|
102
|
+
# <tt>ActiveRecord::RecordNotUnique</tt> is raised.
|
103
|
+
#
|
104
|
+
# Unique indexes can be identified by columns or name:
|
105
|
+
#
|
106
|
+
# unique_by: :isbn
|
107
|
+
# unique_by: %i[ author_id name ]
|
108
|
+
# unique_by: :index_books_on_isbn
|
109
|
+
#
|
110
|
+
# Because it relies on the index information from the database
|
111
|
+
# <tt>:unique_by</tt> is recommended to be paired with
|
112
|
+
# Active Record's schema_cache.
|
113
|
+
#
|
114
|
+
# ==== Example
|
115
|
+
#
|
116
|
+
# # Insert records and skip inserting any duplicates.
|
117
|
+
# # Here "Eloquent Ruby" is skipped because its id is not unique.
|
118
|
+
#
|
119
|
+
# Book.insert_all([
|
120
|
+
# { id: 1, title: "Rework", author: "David" },
|
121
|
+
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
122
|
+
# ])
|
123
|
+
def insert_all(attributes, returning: nil, unique_by: nil)
|
124
|
+
InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
|
125
|
+
end
|
126
|
+
|
127
|
+
# Inserts a single record into the database in a single SQL INSERT
|
128
|
+
# statement. It does not instantiate any models nor does it trigger
|
129
|
+
# Active Record callbacks or validations. Though passed values
|
130
|
+
# go through Active Record's type casting and serialization.
|
131
|
+
#
|
132
|
+
# See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
|
133
|
+
def insert!(attributes, returning: nil)
|
134
|
+
insert_all!([ attributes ], returning: returning)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Inserts multiple records into the database in a single SQL INSERT
|
138
|
+
# statement. It does not instantiate any models nor does it trigger
|
139
|
+
# Active Record callbacks or validations. Though passed values
|
140
|
+
# go through Active Record's type casting and serialization.
|
141
|
+
#
|
142
|
+
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
143
|
+
# the attributes for a single row and must have the same keys.
|
144
|
+
#
|
145
|
+
# Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
|
146
|
+
# unique index on the table. In that case, no rows are inserted.
|
147
|
+
#
|
148
|
+
# To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
|
149
|
+
# To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
|
150
|
+
#
|
151
|
+
# Returns an <tt>ActiveRecord::Result</tt> with its contents based on
|
152
|
+
# <tt>:returning</tt> (see below).
|
153
|
+
#
|
154
|
+
# ==== Options
|
155
|
+
#
|
156
|
+
# [:returning]
|
157
|
+
# (PostgreSQL only) An array of attributes to return for all successfully
|
158
|
+
# inserted records, which by default is the primary key.
|
159
|
+
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
160
|
+
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
161
|
+
# clause entirely.
|
162
|
+
#
|
163
|
+
# ==== Examples
|
164
|
+
#
|
165
|
+
# # Insert multiple records
|
166
|
+
# Book.insert_all!([
|
167
|
+
# { title: "Rework", author: "David" },
|
168
|
+
# { title: "Eloquent Ruby", author: "Russ" }
|
169
|
+
# ])
|
170
|
+
#
|
171
|
+
# # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
|
172
|
+
# # does not have a unique id.
|
173
|
+
# Book.insert_all!([
|
174
|
+
# { id: 1, title: "Rework", author: "David" },
|
175
|
+
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
176
|
+
# ])
|
177
|
+
def insert_all!(attributes, returning: nil)
|
178
|
+
InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
|
179
|
+
end
|
180
|
+
|
181
|
+
# Updates or inserts (upserts) a single record into the database in a
|
182
|
+
# single SQL INSERT statement. It does not instantiate any models nor does
|
183
|
+
# it trigger Active Record callbacks or validations. Though passed values
|
184
|
+
# go through Active Record's type casting and serialization.
|
185
|
+
#
|
186
|
+
# See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
|
187
|
+
def upsert(attributes, returning: nil, unique_by: nil)
|
188
|
+
upsert_all([ attributes ], returning: returning, unique_by: unique_by)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Updates or inserts (upserts) multiple records into the database in a
|
192
|
+
# single SQL INSERT statement. It does not instantiate any models nor does
|
193
|
+
# it trigger Active Record callbacks or validations. Though passed values
|
194
|
+
# go through Active Record's type casting and serialization.
|
195
|
+
#
|
196
|
+
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
197
|
+
# the attributes for a single row and must have the same keys.
|
198
|
+
#
|
199
|
+
# Returns an <tt>ActiveRecord::Result</tt> with its contents based on
|
200
|
+
# <tt>:returning</tt> (see below).
|
201
|
+
#
|
202
|
+
# ==== Options
|
203
|
+
#
|
204
|
+
# [:returning]
|
205
|
+
# (PostgreSQL only) An array of attributes to return for all successfully
|
206
|
+
# inserted records, which by default is the primary key.
|
207
|
+
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
208
|
+
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
209
|
+
# clause entirely.
|
210
|
+
#
|
211
|
+
# [:unique_by]
|
212
|
+
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
213
|
+
# by every unique index on the table. Any duplicate rows are skipped.
|
214
|
+
#
|
215
|
+
# To skip rows according to just one unique index pass <tt>:unique_by</tt>.
|
216
|
+
#
|
217
|
+
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
218
|
+
# row has an existing id, or is not unique by another unique index,
|
219
|
+
# <tt>ActiveRecord::RecordNotUnique</tt> is raised.
|
220
|
+
#
|
221
|
+
# Unique indexes can be identified by columns or name:
|
222
|
+
#
|
223
|
+
# unique_by: :isbn
|
224
|
+
# unique_by: %i[ author_id name ]
|
225
|
+
# unique_by: :index_books_on_isbn
|
226
|
+
#
|
227
|
+
# Because it relies on the index information from the database
|
228
|
+
# <tt>:unique_by</tt> is recommended to be paired with
|
229
|
+
# Active Record's schema_cache.
|
230
|
+
#
|
231
|
+
# ==== Examples
|
232
|
+
#
|
233
|
+
# # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
|
234
|
+
# # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
|
235
|
+
#
|
236
|
+
# Book.upsert_all([
|
237
|
+
# { title: "Rework", author: "David", isbn: "1" },
|
238
|
+
# { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
|
239
|
+
# ], unique_by: :isbn)
|
240
|
+
#
|
241
|
+
# Book.find_by(isbn: "1").title # => "Eloquent Ruby"
|
242
|
+
def upsert_all(attributes, returning: nil, unique_by: nil)
|
243
|
+
InsertAll.new(self, attributes, on_duplicate: :update, returning: returning, unique_by: unique_by).execute
|
244
|
+
end
|
245
|
+
|
58
246
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
59
247
|
# the appropriate class. Accepts only keys as strings.
|
60
248
|
#
|
@@ -67,8 +255,7 @@ module ActiveRecord
|
|
67
255
|
# how this "single-table" inheritance mapping is implemented.
|
68
256
|
def instantiate(attributes, column_types = {}, &block)
|
69
257
|
klass = discriminate_class_for_record(attributes)
|
70
|
-
|
71
|
-
klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
|
258
|
+
instantiate_instance_of(klass, attributes, column_types, &block)
|
72
259
|
end
|
73
260
|
|
74
261
|
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
|
@@ -97,11 +284,13 @@ module ActiveRecord
|
|
97
284
|
# When running callbacks is not needed for each record update,
|
98
285
|
# it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
|
99
286
|
# for updating all records in a single query.
|
100
|
-
def update(id, attributes)
|
287
|
+
def update(id = :all, attributes)
|
101
288
|
if id.is_a?(Array)
|
102
289
|
id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
|
103
290
|
object.update(attributes[idx])
|
104
291
|
}
|
292
|
+
elsif id == :all
|
293
|
+
all.each { |record| record.update(attributes) }
|
105
294
|
else
|
106
295
|
if ActiveRecord::Base === id
|
107
296
|
raise ArgumentError,
|
@@ -141,7 +330,7 @@ module ActiveRecord
|
|
141
330
|
end
|
142
331
|
end
|
143
332
|
|
144
|
-
# Deletes the row with a primary key matching the +id+ argument, using
|
333
|
+
# Deletes the row with a primary key matching the +id+ argument, using an
|
145
334
|
# SQL +DELETE+ statement, and returns the number of rows deleted. Active
|
146
335
|
# Record objects are not instantiated, so the object's callbacks are not
|
147
336
|
# executed, including any <tt>:dependent</tt> association options.
|
@@ -160,10 +349,11 @@ module ActiveRecord
|
|
160
349
|
# # Delete multiple rows
|
161
350
|
# Todo.delete([2,3,4])
|
162
351
|
def delete(id_or_array)
|
163
|
-
|
352
|
+
delete_by(primary_key => id_or_array)
|
164
353
|
end
|
165
354
|
|
166
355
|
def _insert_record(values) # :nodoc:
|
356
|
+
primary_key = self.primary_key
|
167
357
|
primary_key_value = nil
|
168
358
|
|
169
359
|
if primary_key && Hash === values
|
@@ -176,7 +366,7 @@ module ActiveRecord
|
|
176
366
|
end
|
177
367
|
|
178
368
|
if values.empty?
|
179
|
-
im = arel_table.compile_insert(connection.empty_insert_statement_value)
|
369
|
+
im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
|
180
370
|
im.into arel_table
|
181
371
|
else
|
182
372
|
im = arel_table.compile_insert(_substitute_values(values))
|
@@ -206,6 +396,13 @@ module ActiveRecord
|
|
206
396
|
end
|
207
397
|
|
208
398
|
private
|
399
|
+
# Given a class, an attributes hash, +instantiate_instance_of+ returns a
|
400
|
+
# new instance of the class. Accepts only keys as strings.
|
401
|
+
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
|
402
|
+
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
|
403
|
+
klass.allocate.init_with_attributes(attributes, &block)
|
404
|
+
end
|
405
|
+
|
209
406
|
# Called by +instantiate+ to decide which class to use for a new
|
210
407
|
# record instance.
|
211
408
|
#
|
@@ -227,20 +424,20 @@ module ActiveRecord
|
|
227
424
|
# Returns true if this object hasn't been saved yet -- that is, a record
|
228
425
|
# for the object doesn't exist in the database yet; otherwise, returns false.
|
229
426
|
def new_record?
|
230
|
-
sync_with_transaction_state
|
427
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
231
428
|
@new_record
|
232
429
|
end
|
233
430
|
|
234
431
|
# Returns true if this object has been destroyed, otherwise returns false.
|
235
432
|
def destroyed?
|
236
|
-
sync_with_transaction_state
|
433
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
237
434
|
@destroyed
|
238
435
|
end
|
239
436
|
|
240
437
|
# Returns true if the record is persisted, i.e. it's not a new record and it was
|
241
438
|
# not destroyed, otherwise returns false.
|
242
439
|
def persisted?
|
243
|
-
sync_with_transaction_state
|
440
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
244
441
|
!(@new_record || @destroyed)
|
245
442
|
end
|
246
443
|
|
@@ -334,7 +531,6 @@ module ActiveRecord
|
|
334
531
|
def destroy
|
335
532
|
_raise_readonly_record_error if readonly?
|
336
533
|
destroy_associations
|
337
|
-
self.class.connection.add_transaction_record(self)
|
338
534
|
@_trigger_destroy_callback = if persisted?
|
339
535
|
destroy_row > 0
|
340
536
|
else
|
@@ -372,7 +568,6 @@ module ActiveRecord
|
|
372
568
|
became.send(:initialize)
|
373
569
|
became.instance_variable_set("@attributes", @attributes)
|
374
570
|
became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
|
375
|
-
became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
|
376
571
|
became.instance_variable_set("@new_record", new_record?)
|
377
572
|
became.instance_variable_set("@destroyed", destroyed?)
|
378
573
|
became.errors.copy!(errors)
|
@@ -428,6 +623,7 @@ module ActiveRecord
|
|
428
623
|
end
|
429
624
|
|
430
625
|
alias update_attributes update
|
626
|
+
deprecate update_attributes: "please, use update instead"
|
431
627
|
|
432
628
|
# Updates its receiver just like #update but calls #save! instead
|
433
629
|
# of +save+, so an exception is raised if the record is invalid and saving will fail.
|
@@ -441,6 +637,7 @@ module ActiveRecord
|
|
441
637
|
end
|
442
638
|
|
443
639
|
alias update_attributes! update!
|
640
|
+
deprecate update_attributes!: "please, use update! instead"
|
444
641
|
|
445
642
|
# Equivalent to <code>update_columns(name => value)</code>.
|
446
643
|
def update_column(name, value)
|
@@ -467,8 +664,13 @@ module ActiveRecord
|
|
467
664
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
468
665
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
469
666
|
|
667
|
+
attributes = attributes.transform_keys do |key|
|
668
|
+
name = key.to_s
|
669
|
+
self.class.attribute_aliases[name] || name
|
670
|
+
end
|
671
|
+
|
470
672
|
attributes.each_key do |key|
|
471
|
-
verify_readonly_attribute(key
|
673
|
+
verify_readonly_attribute(key)
|
472
674
|
end
|
473
675
|
|
474
676
|
id_in_database = self.id_in_database
|
@@ -478,7 +680,7 @@ module ActiveRecord
|
|
478
680
|
|
479
681
|
affected_rows = self.class._update_record(
|
480
682
|
attributes,
|
481
|
-
|
683
|
+
@primary_key => id_in_database
|
482
684
|
)
|
483
685
|
|
484
686
|
affected_rows == 1
|
@@ -655,7 +857,9 @@ module ActiveRecord
|
|
655
857
|
end
|
656
858
|
|
657
859
|
attribute_names = timestamp_attributes_for_update_in_model
|
658
|
-
attribute_names |= names.map(&:to_s)
|
860
|
+
attribute_names |= names.map!(&:to_s).map! { |name|
|
861
|
+
self.class.attribute_aliases[name] || name
|
862
|
+
}
|
659
863
|
|
660
864
|
unless attribute_names.empty?
|
661
865
|
affected_rows = _touch_row(attribute_names, time)
|
@@ -676,15 +880,14 @@ module ActiveRecord
|
|
676
880
|
end
|
677
881
|
|
678
882
|
def _delete_row
|
679
|
-
self.class._delete_record(
|
883
|
+
self.class._delete_record(@primary_key => id_in_database)
|
680
884
|
end
|
681
885
|
|
682
886
|
def _touch_row(attribute_names, time)
|
683
887
|
time ||= current_time_from_proper_timezone
|
684
888
|
|
685
889
|
attribute_names.each do |attr_name|
|
686
|
-
|
687
|
-
clear_attribute_change(attr_name)
|
890
|
+
_write_attribute(attr_name, time)
|
688
891
|
end
|
689
892
|
|
690
893
|
_update_row(attribute_names, "touch")
|
@@ -693,21 +896,20 @@ module ActiveRecord
|
|
693
896
|
def _update_row(attribute_names, attempted_action = "update")
|
694
897
|
self.class._update_record(
|
695
898
|
attributes_with_values(attribute_names),
|
696
|
-
|
899
|
+
@primary_key => id_in_database
|
697
900
|
)
|
698
901
|
end
|
699
902
|
|
700
|
-
def create_or_update(
|
903
|
+
def create_or_update(**, &block)
|
701
904
|
_raise_readonly_record_error if readonly?
|
702
905
|
return false if destroyed?
|
703
|
-
result = new_record? ? _create_record(&block) : _update_record(
|
906
|
+
result = new_record? ? _create_record(&block) : _update_record(&block)
|
704
907
|
result != false
|
705
908
|
end
|
706
909
|
|
707
910
|
# Updates the associated record with values matching those of the instance attributes.
|
708
911
|
# Returns the number of affected rows.
|
709
912
|
def _update_record(attribute_names = self.attribute_names)
|
710
|
-
attribute_names &= self.class.column_names
|
711
913
|
attribute_names = attributes_for_update(attribute_names)
|
712
914
|
|
713
915
|
if attribute_names.empty?
|
@@ -726,11 +928,13 @@ module ActiveRecord
|
|
726
928
|
# Creates a record with values matching those of the instance attributes
|
727
929
|
# and returns its id.
|
728
930
|
def _create_record(attribute_names = self.attribute_names)
|
729
|
-
attribute_names
|
730
|
-
|
931
|
+
attribute_names = attributes_for_create(attribute_names)
|
932
|
+
|
933
|
+
new_id = self.class._insert_record(
|
934
|
+
attributes_with_values(attribute_names)
|
935
|
+
)
|
731
936
|
|
732
|
-
new_id
|
733
|
-
self.id ||= new_id if self.class.primary_key
|
937
|
+
self.id ||= new_id if @primary_key
|
734
938
|
|
735
939
|
@new_record = false
|
736
940
|
|
@@ -750,6 +954,8 @@ module ActiveRecord
|
|
750
954
|
@_association_destroy_exception = nil
|
751
955
|
end
|
752
956
|
|
957
|
+
# The name of the method used to touch a +belongs_to+ association when the
|
958
|
+
# +:touch+ option is used.
|
753
959
|
def belongs_to_touch_method
|
754
960
|
:touch
|
755
961
|
end
|
@@ -26,15 +26,22 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.run
|
29
|
-
|
30
|
-
|
29
|
+
pools = []
|
30
|
+
|
31
|
+
ActiveRecord::Base.connection_handlers.each do |key, handler|
|
32
|
+
pools << handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
|
33
|
+
end
|
34
|
+
|
35
|
+
pools.flatten
|
31
36
|
end
|
32
37
|
|
33
38
|
def self.complete(pools)
|
34
39
|
pools.each { |pool| pool.disable_query_cache! }
|
35
40
|
|
36
|
-
ActiveRecord::Base.
|
37
|
-
|
41
|
+
ActiveRecord::Base.connection_handlers.each do |_, handler|
|
42
|
+
handler.connection_pool_list.each do |pool|
|
43
|
+
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
44
|
+
end
|
38
45
|
end
|
39
46
|
end
|
40
47
|
|