activerecord 5.2.4.2 → 6.0.2.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 +715 -566
- 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 +3 -13
- 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 +12 -23
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- 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 +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -31
- 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 +2 -2
- 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 +104 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
- 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 +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +187 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
- 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 +6 -10
- 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 +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- 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 +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +129 -141
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +103 -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 +15 -7
- 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 +76 -49
- 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 +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- 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 +32 -30
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +23 -27
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- 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 +13 -8
- data/lib/active_record/relation/query_methods.rb +213 -64
- 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 +4 -5
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +30 -3
- 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 +56 -65
- 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 +109 -24
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -14,6 +14,8 @@ module ActiveRecord
|
|
14
14
|
# * change_column
|
15
15
|
# * change_column_default (must supply a :from and :to option)
|
16
16
|
# * change_column_null
|
17
|
+
# * change_column_comment (must supply a :from and :to option)
|
18
|
+
# * change_table_comment (must supply a :from and :to option)
|
17
19
|
# * create_join_table
|
18
20
|
# * create_table
|
19
21
|
# * disable_extension
|
@@ -35,7 +37,8 @@ module ActiveRecord
|
|
35
37
|
:change_column_default, :add_reference, :remove_reference, :transaction,
|
36
38
|
:drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
|
37
39
|
:change_column, :execute, :remove_columns, :change_column_null,
|
38
|
-
:add_foreign_key, :remove_foreign_key
|
40
|
+
:add_foreign_key, :remove_foreign_key,
|
41
|
+
:change_column_comment, :change_table_comment
|
39
42
|
]
|
40
43
|
include JoinTable
|
41
44
|
|
@@ -85,7 +88,7 @@ module ActiveRecord
|
|
85
88
|
# invert the +command+.
|
86
89
|
def inverse_of(command, args, &block)
|
87
90
|
method = :"invert_#{command}"
|
88
|
-
raise IrreversibleMigration,
|
91
|
+
raise IrreversibleMigration, <<~MSG unless respond_to?(method, true)
|
89
92
|
This migration uses #{command}, which is not automatically reversible.
|
90
93
|
To make the migration reversible you can either:
|
91
94
|
1. Define #up and #down methods in place of the #change method.
|
@@ -108,11 +111,17 @@ module ActiveRecord
|
|
108
111
|
yield delegate.update_table_definition(table_name, self)
|
109
112
|
end
|
110
113
|
|
114
|
+
def replay(migration)
|
115
|
+
commands.each do |cmd, args, block|
|
116
|
+
migration.send(cmd, *args, &block)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
111
120
|
private
|
112
121
|
|
113
122
|
module StraightReversions # :nodoc:
|
114
123
|
private
|
115
|
-
{
|
124
|
+
{
|
116
125
|
execute_block: :execute_block,
|
117
126
|
create_table: :drop_table,
|
118
127
|
create_join_table: :drop_join_table,
|
@@ -133,6 +142,17 @@ module ActiveRecord
|
|
133
142
|
|
134
143
|
include StraightReversions
|
135
144
|
|
145
|
+
def invert_transaction(args)
|
146
|
+
sub_recorder = CommandRecorder.new(delegate)
|
147
|
+
sub_recorder.revert { yield }
|
148
|
+
|
149
|
+
invertions_proc = proc {
|
150
|
+
sub_recorder.replay(self)
|
151
|
+
}
|
152
|
+
|
153
|
+
[:transaction, args, invertions_proc]
|
154
|
+
end
|
155
|
+
|
136
156
|
def invert_drop_table(args, &block)
|
137
157
|
if args.size == 1 && block == nil
|
138
158
|
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
|
@@ -214,15 +234,39 @@ module ActiveRecord
|
|
214
234
|
end
|
215
235
|
|
216
236
|
def invert_remove_foreign_key(args)
|
217
|
-
|
218
|
-
|
237
|
+
options = args.extract_options!
|
238
|
+
from_table, to_table = args
|
239
|
+
|
240
|
+
to_table ||= options.delete(:to_table)
|
241
|
+
|
242
|
+
raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil?
|
219
243
|
|
220
244
|
reversed_args = [from_table, to_table]
|
221
|
-
reversed_args <<
|
245
|
+
reversed_args << options unless options.empty?
|
222
246
|
|
223
247
|
[:add_foreign_key, reversed_args]
|
224
248
|
end
|
225
249
|
|
250
|
+
def invert_change_column_comment(args)
|
251
|
+
table, column, options = *args
|
252
|
+
|
253
|
+
unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
254
|
+
raise ActiveRecord::IrreversibleMigration, "change_column_comment is only reversible if given a :from and :to option."
|
255
|
+
end
|
256
|
+
|
257
|
+
[:change_column_comment, [table, column, from: options[:to], to: options[:from]]]
|
258
|
+
end
|
259
|
+
|
260
|
+
def invert_change_table_comment(args)
|
261
|
+
table, options = *args
|
262
|
+
|
263
|
+
unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
264
|
+
raise ActiveRecord::IrreversibleMigration, "change_table_comment is only reversible if given a :from and :to option."
|
265
|
+
end
|
266
|
+
|
267
|
+
[:change_table_comment, [table, from: options[:to], to: options[:from]]]
|
268
|
+
end
|
269
|
+
|
226
270
|
def respond_to_missing?(method, _)
|
227
271
|
super || delegate.respond_to?(method)
|
228
272
|
end
|
@@ -13,7 +13,77 @@ module ActiveRecord
|
|
13
13
|
const_get(name)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
V6_0 = Current
|
17
|
+
|
18
|
+
class V5_2 < V6_0
|
19
|
+
module TableDefinition
|
20
|
+
def timestamps(**options)
|
21
|
+
options[:precision] ||= nil
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module CommandRecorder
|
27
|
+
def invert_transaction(args, &block)
|
28
|
+
[:transaction, args, block]
|
29
|
+
end
|
30
|
+
|
31
|
+
def invert_change_column_comment(args)
|
32
|
+
table_name, column_name, comment = args
|
33
|
+
[:change_column_comment, [table_name, column_name, from: comment, to: comment]]
|
34
|
+
end
|
35
|
+
|
36
|
+
def invert_change_table_comment(args)
|
37
|
+
table_name, comment = args
|
38
|
+
[:change_table_comment, [table_name, from: comment, to: comment]]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_table(table_name, **options)
|
43
|
+
if block_given?
|
44
|
+
super { |t| yield compatible_table_definition(t) }
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def change_table(table_name, **options)
|
51
|
+
if block_given?
|
52
|
+
super { |t| yield compatible_table_definition(t) }
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_join_table(table_1, table_2, **options)
|
59
|
+
if block_given?
|
60
|
+
super { |t| yield compatible_table_definition(t) }
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_timestamps(table_name, **options)
|
67
|
+
options[:precision] ||= nil
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def compatible_table_definition(t)
|
73
|
+
class << t
|
74
|
+
prepend TableDefinition
|
75
|
+
end
|
76
|
+
t
|
77
|
+
end
|
78
|
+
|
79
|
+
def command_recorder
|
80
|
+
recorder = super
|
81
|
+
class << recorder
|
82
|
+
prepend CommandRecorder
|
83
|
+
end
|
84
|
+
recorder
|
85
|
+
end
|
86
|
+
end
|
17
87
|
|
18
88
|
class V5_1 < V5_2
|
19
89
|
def change_column(table_name, column_name, type, options = {})
|
@@ -69,35 +139,12 @@ module ActiveRecord
|
|
69
139
|
options[:id] = :integer
|
70
140
|
end
|
71
141
|
|
72
|
-
|
73
|
-
super do |t|
|
74
|
-
yield compatible_table_definition(t)
|
75
|
-
end
|
76
|
-
else
|
77
|
-
super
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def change_table(table_name, options = {})
|
82
|
-
if block_given?
|
83
|
-
super do |t|
|
84
|
-
yield compatible_table_definition(t)
|
85
|
-
end
|
86
|
-
else
|
87
|
-
super
|
88
|
-
end
|
142
|
+
super
|
89
143
|
end
|
90
144
|
|
91
145
|
def create_join_table(table_1, table_2, column_options: {}, **options)
|
92
146
|
column_options.reverse_merge!(type: :integer)
|
93
|
-
|
94
|
-
if block_given?
|
95
|
-
super do |t|
|
96
|
-
yield compatible_table_definition(t)
|
97
|
-
end
|
98
|
-
else
|
99
|
-
super
|
100
|
-
end
|
147
|
+
super
|
101
148
|
end
|
102
149
|
|
103
150
|
def add_column(table_name, column_name, type, options = {})
|
@@ -118,7 +165,7 @@ module ActiveRecord
|
|
118
165
|
class << t
|
119
166
|
prepend TableDefinition
|
120
167
|
end
|
121
|
-
|
168
|
+
super
|
122
169
|
end
|
123
170
|
end
|
124
171
|
|
@@ -136,33 +183,13 @@ module ActiveRecord
|
|
136
183
|
end
|
137
184
|
end
|
138
185
|
|
139
|
-
def
|
140
|
-
if block_given?
|
141
|
-
super do |t|
|
142
|
-
yield compatible_table_definition(t)
|
143
|
-
end
|
144
|
-
else
|
145
|
-
super
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def change_table(table_name, options = {})
|
150
|
-
if block_given?
|
151
|
-
super do |t|
|
152
|
-
yield compatible_table_definition(t)
|
153
|
-
end
|
154
|
-
else
|
155
|
-
super
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def add_reference(*, **options)
|
186
|
+
def add_reference(table_name, ref_name, **options)
|
160
187
|
options[:index] ||= false
|
161
188
|
super
|
162
189
|
end
|
163
190
|
alias :add_belongs_to :add_reference
|
164
191
|
|
165
|
-
def add_timestamps(
|
192
|
+
def add_timestamps(table_name, **options)
|
166
193
|
options[:null] = true if options[:null].nil?
|
167
194
|
super
|
168
195
|
end
|
@@ -102,6 +102,21 @@ module ActiveRecord
|
|
102
102
|
# If true, the default table name for a Product class will be "products". If false, it would just be "product".
|
103
103
|
# See table_name for the full rules on table/class naming. This is true, by default.
|
104
104
|
|
105
|
+
##
|
106
|
+
# :singleton-method: implicit_order_column
|
107
|
+
# :call-seq: implicit_order_column
|
108
|
+
#
|
109
|
+
# The name of the column records are ordered by if no explicit order clause
|
110
|
+
# is used during an ordered finder call. If not set the primary key is used.
|
111
|
+
|
112
|
+
##
|
113
|
+
# :singleton-method: implicit_order_column=
|
114
|
+
# :call-seq: implicit_order_column=(column_name)
|
115
|
+
#
|
116
|
+
# Sets the column to sort records by when no explicit order clause is used
|
117
|
+
# during an ordered finder call. Useful when the primary key is not an
|
118
|
+
# auto-incrementing integer, for example when it's a UUID. Note that using
|
119
|
+
# a non-unique column can result in non-deterministic results.
|
105
120
|
included do
|
106
121
|
mattr_accessor :primary_key_prefix_type, instance_writer: false
|
107
122
|
|
@@ -110,6 +125,7 @@ module ActiveRecord
|
|
110
125
|
class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
|
111
126
|
class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
|
112
127
|
class_attribute :pluralize_table_names, instance_writer: false, default: true
|
128
|
+
class_attribute :implicit_order_column, instance_accessor: false
|
113
129
|
|
114
130
|
self.protected_environments = ["production"]
|
115
131
|
self.inheritance_column = "type"
|
@@ -218,11 +234,11 @@ module ActiveRecord
|
|
218
234
|
end
|
219
235
|
|
220
236
|
def full_table_name_prefix #:nodoc:
|
221
|
-
(
|
237
|
+
(module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
|
222
238
|
end
|
223
239
|
|
224
240
|
def full_table_name_suffix #:nodoc:
|
225
|
-
(
|
241
|
+
(module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
|
226
242
|
end
|
227
243
|
|
228
244
|
# The array of names of environments where destructive actions should be prohibited. By default,
|
@@ -276,7 +292,7 @@ module ActiveRecord
|
|
276
292
|
end
|
277
293
|
|
278
294
|
def sequence_name
|
279
|
-
if base_class
|
295
|
+
if base_class?
|
280
296
|
@sequence_name ||= reset_sequence_name
|
281
297
|
else
|
282
298
|
(@sequence_name ||= nil) || base_class.sequence_name
|
@@ -388,6 +404,11 @@ module ActiveRecord
|
|
388
404
|
@column_names ||= columns.map(&:name)
|
389
405
|
end
|
390
406
|
|
407
|
+
def symbol_column_to_string(name_symbol) # :nodoc:
|
408
|
+
@symbol_column_to_string_name_hash ||= column_names.index_by(&:to_sym)
|
409
|
+
@symbol_column_to_string_name_hash[name_symbol]
|
410
|
+
end
|
411
|
+
|
391
412
|
# Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
|
392
413
|
# and columns used for single table inheritance have been removed.
|
393
414
|
def content_columns
|
@@ -459,6 +480,9 @@ module ActiveRecord
|
|
459
480
|
load_schema!
|
460
481
|
|
461
482
|
@schema_loaded = true
|
483
|
+
rescue
|
484
|
+
reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
|
485
|
+
raise
|
462
486
|
end
|
463
487
|
end
|
464
488
|
|
@@ -477,6 +501,7 @@ module ActiveRecord
|
|
477
501
|
def reload_schema_from_cache
|
478
502
|
@arel_table = nil
|
479
503
|
@column_names = nil
|
504
|
+
@symbol_column_to_string_name_hash = nil
|
480
505
|
@attribute_types = nil
|
481
506
|
@content_columns = nil
|
482
507
|
@default_attributes = nil
|
@@ -501,19 +526,18 @@ module ActiveRecord
|
|
501
526
|
|
502
527
|
# Computes and returns a table name according to default conventions.
|
503
528
|
def compute_table_name
|
504
|
-
|
505
|
-
if self == base
|
529
|
+
if base_class?
|
506
530
|
# Nested classes are prefixed with singular parent table name.
|
507
|
-
if
|
508
|
-
contained =
|
509
|
-
contained = contained.singularize if
|
531
|
+
if module_parent < Base && !module_parent.abstract_class?
|
532
|
+
contained = module_parent.table_name
|
533
|
+
contained = contained.singularize if module_parent.pluralize_table_names
|
510
534
|
contained += "_"
|
511
535
|
end
|
512
536
|
|
513
537
|
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
|
514
538
|
else
|
515
539
|
# STI subclasses always use their superclass' table.
|
516
|
-
|
540
|
+
base_class.table_name
|
517
541
|
end
|
518
542
|
end
|
519
543
|
end
|
@@ -426,7 +426,7 @@ module ActiveRecord
|
|
426
426
|
existing_record.assign_attributes(assignable_attributes)
|
427
427
|
association(association_name).initialize_attributes(existing_record)
|
428
428
|
else
|
429
|
-
method = "build_#{association_name}"
|
429
|
+
method = :"build_#{association_name}"
|
430
430
|
if respond_to?(method)
|
431
431
|
send(method, assignable_attributes)
|
432
432
|
else
|
@@ -501,7 +501,7 @@ module ActiveRecord
|
|
501
501
|
|
502
502
|
if attributes["id"].blank?
|
503
503
|
unless reject_new_record?(association_name, attributes)
|
504
|
-
association.build(attributes.except(*UNASSIGNABLE_KEYS))
|
504
|
+
association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
|
505
505
|
end
|
506
506
|
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
|
507
507
|
unless call_reject_if(association_name, attributes)
|
@@ -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.
|
@@ -143,7 +330,7 @@ module ActiveRecord
|
|
143
330
|
end
|
144
331
|
end
|
145
332
|
|
146
|
-
# 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
|
147
334
|
# SQL +DELETE+ statement, and returns the number of rows deleted. Active
|
148
335
|
# Record objects are not instantiated, so the object's callbacks are not
|
149
336
|
# executed, including any <tt>:dependent</tt> association options.
|
@@ -162,10 +349,11 @@ module ActiveRecord
|
|
162
349
|
# # Delete multiple rows
|
163
350
|
# Todo.delete([2,3,4])
|
164
351
|
def delete(id_or_array)
|
165
|
-
|
352
|
+
delete_by(primary_key => id_or_array)
|
166
353
|
end
|
167
354
|
|
168
355
|
def _insert_record(values) # :nodoc:
|
356
|
+
primary_key = self.primary_key
|
169
357
|
primary_key_value = nil
|
170
358
|
|
171
359
|
if primary_key && Hash === values
|
@@ -178,7 +366,7 @@ module ActiveRecord
|
|
178
366
|
end
|
179
367
|
|
180
368
|
if values.empty?
|
181
|
-
im = arel_table.compile_insert(connection.empty_insert_statement_value)
|
369
|
+
im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
|
182
370
|
im.into arel_table
|
183
371
|
else
|
184
372
|
im = arel_table.compile_insert(_substitute_values(values))
|
@@ -208,6 +396,13 @@ module ActiveRecord
|
|
208
396
|
end
|
209
397
|
|
210
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
|
+
|
211
406
|
# Called by +instantiate+ to decide which class to use for a new
|
212
407
|
# record instance.
|
213
408
|
#
|
@@ -229,20 +424,20 @@ module ActiveRecord
|
|
229
424
|
# Returns true if this object hasn't been saved yet -- that is, a record
|
230
425
|
# for the object doesn't exist in the database yet; otherwise, returns false.
|
231
426
|
def new_record?
|
232
|
-
sync_with_transaction_state
|
427
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
233
428
|
@new_record
|
234
429
|
end
|
235
430
|
|
236
431
|
# Returns true if this object has been destroyed, otherwise returns false.
|
237
432
|
def destroyed?
|
238
|
-
sync_with_transaction_state
|
433
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
239
434
|
@destroyed
|
240
435
|
end
|
241
436
|
|
242
437
|
# Returns true if the record is persisted, i.e. it's not a new record and it was
|
243
438
|
# not destroyed, otherwise returns false.
|
244
439
|
def persisted?
|
245
|
-
sync_with_transaction_state
|
440
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
246
441
|
!(@new_record || @destroyed)
|
247
442
|
end
|
248
443
|
|
@@ -336,7 +531,6 @@ module ActiveRecord
|
|
336
531
|
def destroy
|
337
532
|
_raise_readonly_record_error if readonly?
|
338
533
|
destroy_associations
|
339
|
-
self.class.connection.add_transaction_record(self)
|
340
534
|
@_trigger_destroy_callback = if persisted?
|
341
535
|
destroy_row > 0
|
342
536
|
else
|
@@ -374,7 +568,6 @@ module ActiveRecord
|
|
374
568
|
became.send(:initialize)
|
375
569
|
became.instance_variable_set("@attributes", @attributes)
|
376
570
|
became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
|
377
|
-
became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
|
378
571
|
became.instance_variable_set("@new_record", new_record?)
|
379
572
|
became.instance_variable_set("@destroyed", destroyed?)
|
380
573
|
became.errors.copy!(errors)
|
@@ -430,6 +623,7 @@ module ActiveRecord
|
|
430
623
|
end
|
431
624
|
|
432
625
|
alias update_attributes update
|
626
|
+
deprecate update_attributes: "please, use update instead"
|
433
627
|
|
434
628
|
# Updates its receiver just like #update but calls #save! instead
|
435
629
|
# of +save+, so an exception is raised if the record is invalid and saving will fail.
|
@@ -443,6 +637,7 @@ module ActiveRecord
|
|
443
637
|
end
|
444
638
|
|
445
639
|
alias update_attributes! update!
|
640
|
+
deprecate update_attributes!: "please, use update! instead"
|
446
641
|
|
447
642
|
# Equivalent to <code>update_columns(name => value)</code>.
|
448
643
|
def update_column(name, value)
|
@@ -469,8 +664,13 @@ module ActiveRecord
|
|
469
664
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
470
665
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
471
666
|
|
667
|
+
attributes = attributes.transform_keys do |key|
|
668
|
+
name = key.to_s
|
669
|
+
self.class.attribute_aliases[name] || name
|
670
|
+
end
|
671
|
+
|
472
672
|
attributes.each_key do |key|
|
473
|
-
verify_readonly_attribute(key
|
673
|
+
verify_readonly_attribute(key)
|
474
674
|
end
|
475
675
|
|
476
676
|
id_in_database = self.id_in_database
|
@@ -480,7 +680,7 @@ module ActiveRecord
|
|
480
680
|
|
481
681
|
affected_rows = self.class._update_record(
|
482
682
|
attributes,
|
483
|
-
|
683
|
+
@primary_key => id_in_database
|
484
684
|
)
|
485
685
|
|
486
686
|
affected_rows == 1
|
@@ -657,7 +857,9 @@ module ActiveRecord
|
|
657
857
|
end
|
658
858
|
|
659
859
|
attribute_names = timestamp_attributes_for_update_in_model
|
660
|
-
attribute_names |= names.map(&:to_s)
|
860
|
+
attribute_names |= names.map!(&:to_s).map! { |name|
|
861
|
+
self.class.attribute_aliases[name] || name
|
862
|
+
}
|
661
863
|
|
662
864
|
unless attribute_names.empty?
|
663
865
|
affected_rows = _touch_row(attribute_names, time)
|
@@ -678,15 +880,14 @@ module ActiveRecord
|
|
678
880
|
end
|
679
881
|
|
680
882
|
def _delete_row
|
681
|
-
self.class._delete_record(
|
883
|
+
self.class._delete_record(@primary_key => id_in_database)
|
682
884
|
end
|
683
885
|
|
684
886
|
def _touch_row(attribute_names, time)
|
685
887
|
time ||= current_time_from_proper_timezone
|
686
888
|
|
687
889
|
attribute_names.each do |attr_name|
|
688
|
-
|
689
|
-
clear_attribute_change(attr_name)
|
890
|
+
_write_attribute(attr_name, time)
|
690
891
|
end
|
691
892
|
|
692
893
|
_update_row(attribute_names, "touch")
|
@@ -695,21 +896,20 @@ module ActiveRecord
|
|
695
896
|
def _update_row(attribute_names, attempted_action = "update")
|
696
897
|
self.class._update_record(
|
697
898
|
attributes_with_values(attribute_names),
|
698
|
-
|
899
|
+
@primary_key => id_in_database
|
699
900
|
)
|
700
901
|
end
|
701
902
|
|
702
|
-
def create_or_update(
|
903
|
+
def create_or_update(**, &block)
|
703
904
|
_raise_readonly_record_error if readonly?
|
704
905
|
return false if destroyed?
|
705
|
-
result = new_record? ? _create_record(&block) : _update_record(
|
906
|
+
result = new_record? ? _create_record(&block) : _update_record(&block)
|
706
907
|
result != false
|
707
908
|
end
|
708
909
|
|
709
910
|
# Updates the associated record with values matching those of the instance attributes.
|
710
911
|
# Returns the number of affected rows.
|
711
912
|
def _update_record(attribute_names = self.attribute_names)
|
712
|
-
attribute_names &= self.class.column_names
|
713
913
|
attribute_names = attributes_for_update(attribute_names)
|
714
914
|
|
715
915
|
if attribute_names.empty?
|
@@ -728,11 +928,13 @@ module ActiveRecord
|
|
728
928
|
# Creates a record with values matching those of the instance attributes
|
729
929
|
# and returns its id.
|
730
930
|
def _create_record(attribute_names = self.attribute_names)
|
731
|
-
attribute_names
|
732
|
-
|
931
|
+
attribute_names = attributes_for_create(attribute_names)
|
932
|
+
|
933
|
+
new_id = self.class._insert_record(
|
934
|
+
attributes_with_values(attribute_names)
|
935
|
+
)
|
733
936
|
|
734
|
-
new_id
|
735
|
-
self.id ||= new_id if self.class.primary_key
|
937
|
+
self.id ||= new_id if @primary_key
|
736
938
|
|
737
939
|
@new_record = false
|
738
940
|
|
@@ -752,6 +954,8 @@ module ActiveRecord
|
|
752
954
|
@_association_destroy_exception = nil
|
753
955
|
end
|
754
956
|
|
957
|
+
# The name of the method used to touch a +belongs_to+ association when the
|
958
|
+
# +:touch+ option is used.
|
755
959
|
def belongs_to_touch_method
|
756
960
|
:touch
|
757
961
|
end
|