activerecord 6.0.4.8 → 6.1.0.rc1
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 +764 -883
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +39 -27
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +4 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +52 -48
- data/lib/active_record/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +215 -49
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +33 -23
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +32 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -42
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +59 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +319 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +36 -52
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +30 -31
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
data/lib/active_record/enum.rb
CHANGED
@@ -41,13 +41,20 @@ module ActiveRecord
|
|
41
41
|
# Conversation.where(status: [:active, :archived])
|
42
42
|
# Conversation.where.not(status: :active)
|
43
43
|
#
|
44
|
-
#
|
44
|
+
# Defining scopes can be disabled by setting +:_scopes+ to +false+.
|
45
45
|
#
|
46
|
-
#
|
47
|
-
#
|
46
|
+
# class Conversation < ActiveRecord::Base
|
47
|
+
# enum status: [ :active, :archived ], _scopes: false
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# You can set the default enum value by setting +:_default+, like:
|
51
|
+
#
|
52
|
+
# class Conversation < ActiveRecord::Base
|
53
|
+
# enum status: [ :active, :archived ], _default: "active"
|
48
54
|
# end
|
49
55
|
#
|
50
|
-
#
|
56
|
+
# conversation = Conversation.new
|
57
|
+
# conversation.status # => "active"
|
51
58
|
#
|
52
59
|
# Finally, it's also possible to explicitly map the relation between attribute and
|
53
60
|
# database integer with a hash:
|
@@ -117,28 +124,31 @@ module ActiveRecord
|
|
117
124
|
end
|
118
125
|
|
119
126
|
def cast(value)
|
120
|
-
return if value.blank?
|
121
|
-
|
122
127
|
if mapping.has_key?(value)
|
123
128
|
value.to_s
|
124
129
|
elsif mapping.has_value?(value)
|
125
130
|
mapping.key(value)
|
131
|
+
elsif value.blank?
|
132
|
+
nil
|
126
133
|
else
|
127
134
|
assert_valid_value(value)
|
128
135
|
end
|
129
136
|
end
|
130
137
|
|
131
138
|
def deserialize(value)
|
132
|
-
return if value.nil?
|
133
139
|
mapping.key(subtype.deserialize(value))
|
134
140
|
end
|
135
141
|
|
142
|
+
def serializable?(value)
|
143
|
+
(value.blank? || mapping.has_key?(value) || mapping.has_value?(value)) && super
|
144
|
+
end
|
145
|
+
|
136
146
|
def serialize(value)
|
137
147
|
mapping.fetch(value, value)
|
138
148
|
end
|
139
149
|
|
140
150
|
def assert_valid_value(value)
|
141
|
-
unless
|
151
|
+
unless serializable?(value)
|
142
152
|
raise ArgumentError, "'#{value}' is not a valid #{name}"
|
143
153
|
end
|
144
154
|
end
|
@@ -149,9 +159,14 @@ module ActiveRecord
|
|
149
159
|
|
150
160
|
def enum(definitions)
|
151
161
|
klass = self
|
162
|
+
|
152
163
|
enum_prefix = definitions.delete(:_prefix)
|
153
164
|
enum_suffix = definitions.delete(:_suffix)
|
154
165
|
enum_scopes = definitions.delete(:_scopes)
|
166
|
+
|
167
|
+
default = {}
|
168
|
+
default[:default] = definitions.delete(:_default) if definitions.key?(:_default)
|
169
|
+
|
155
170
|
definitions.each do |name, values|
|
156
171
|
assert_valid_enum_definition_values(values)
|
157
172
|
# statuses = { }
|
@@ -167,13 +182,13 @@ module ActiveRecord
|
|
167
182
|
detect_enum_conflict!(name, "#{name}=")
|
168
183
|
|
169
184
|
attr = attribute_alias?(name) ? attribute_alias(name) : name
|
170
|
-
|
185
|
+
|
186
|
+
decorate_attribute_type(attr, **default) do |subtype|
|
171
187
|
EnumType.new(attr, enum_values, subtype)
|
172
188
|
end
|
173
189
|
|
174
190
|
_enum_methods_module.module_eval do
|
175
191
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
176
|
-
value_method_names = []
|
177
192
|
pairs.each do |label, value|
|
178
193
|
if enum_prefix == true
|
179
194
|
prefix = "#{name}_"
|
@@ -186,8 +201,8 @@ module ActiveRecord
|
|
186
201
|
suffix = "_#{enum_suffix}"
|
187
202
|
end
|
188
203
|
|
189
|
-
|
190
|
-
|
204
|
+
method_friendly_label = label.to_s.gsub(/\W+/, "_")
|
205
|
+
value_method_name = "#{prefix}#{method_friendly_label}#{suffix}"
|
191
206
|
enum_values[label] = value
|
192
207
|
label = label.to_s
|
193
208
|
|
@@ -202,6 +217,8 @@ module ActiveRecord
|
|
202
217
|
# scope :active, -> { where(status: 0) }
|
203
218
|
# scope :not_active, -> { where.not(status: 0) }
|
204
219
|
if enum_scopes != false
|
220
|
+
klass.send(:detect_negative_condition!, value_method_name)
|
221
|
+
|
205
222
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
206
223
|
klass.scope value_method_name, -> { where(attr => value) }
|
207
224
|
|
@@ -209,7 +226,6 @@ module ActiveRecord
|
|
209
226
|
klass.scope "not_#{value_method_name}", -> { where.not(attr => value) }
|
210
227
|
end
|
211
228
|
end
|
212
|
-
klass.send(:detect_negative_enum_conditions!, value_method_names) if enum_scopes != false
|
213
229
|
end
|
214
230
|
enum_values.freeze
|
215
231
|
end
|
@@ -265,16 +281,10 @@ module ActiveRecord
|
|
265
281
|
}
|
266
282
|
end
|
267
283
|
|
268
|
-
def
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
inverted_form = potential_not.sub("not_", "")
|
273
|
-
if method_names.include?(inverted_form)
|
274
|
-
logger.warn "Enum element '#{potential_not}' in #{self.name} uses the prefix 'not_'." \
|
275
|
-
" This has caused a conflict with auto generated negative scopes." \
|
276
|
-
" Avoid using enum elements starting with 'not' where the positive form is also an element."
|
277
|
-
end
|
284
|
+
def detect_negative_condition!(method_name)
|
285
|
+
if method_name.start_with?("not_") && logger
|
286
|
+
logger.warn "An enum element in #{self.name} uses the prefix 'not_'." \
|
287
|
+
" This will cause a conflict with auto generated negative scopes."
|
278
288
|
end
|
279
289
|
end
|
280
290
|
end
|
data/lib/active_record/errors.rb
CHANGED
@@ -7,6 +7,10 @@ module ActiveRecord
|
|
7
7
|
class ActiveRecordError < StandardError
|
8
8
|
end
|
9
9
|
|
10
|
+
# Raised when trying to use a feature in Active Record which requires Active Job but the gem is not present.
|
11
|
+
class ActiveJobRequiredError < ActiveRecordError
|
12
|
+
end
|
13
|
+
|
10
14
|
# Raised when the single-table inheritance mechanism fails to locate the subclass
|
11
15
|
# (for example due to improper usage of column that
|
12
16
|
# {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema::ClassMethods#inheritance_column]
|
@@ -38,6 +42,10 @@ module ActiveRecord
|
|
38
42
|
class AdapterNotSpecified < ActiveRecordError
|
39
43
|
end
|
40
44
|
|
45
|
+
# Raised when a model makes a query but it has not specified an associated table.
|
46
|
+
class TableNotSpecified < ActiveRecordError
|
47
|
+
end
|
48
|
+
|
41
49
|
# Raised when Active Record cannot find database adapter specified in
|
42
50
|
# +config/database.yml+ or programmatically.
|
43
51
|
class AdapterNotFound < ActiveRecordError
|
@@ -49,6 +57,19 @@ module ActiveRecord
|
|
49
57
|
class ConnectionNotEstablished < ActiveRecordError
|
50
58
|
end
|
51
59
|
|
60
|
+
# Raised when a connection could not be obtained within the connection
|
61
|
+
# acquisition timeout period: because max connections in pool
|
62
|
+
# are in use.
|
63
|
+
class ConnectionTimeoutError < ConnectionNotEstablished
|
64
|
+
end
|
65
|
+
|
66
|
+
# Raised when a pool was unable to get ahold of all its connections
|
67
|
+
# to perform a "group" action such as
|
68
|
+
# {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
|
69
|
+
# or {ActiveRecord::Base.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
|
70
|
+
class ExclusiveConnectionTimeoutError < ConnectionTimeoutError
|
71
|
+
end
|
72
|
+
|
52
73
|
# Raised when a write to the database is attempted on a read only connection.
|
53
74
|
class ReadOnlyError < ActiveRecordError
|
54
75
|
end
|
@@ -102,7 +123,7 @@ module ActiveRecord
|
|
102
123
|
# Wraps the underlying database error as +cause+.
|
103
124
|
class StatementInvalid < ActiveRecordError
|
104
125
|
def initialize(message = nil, sql: nil, binds: nil)
|
105
|
-
super(message ||
|
126
|
+
super(message || $!&.message)
|
106
127
|
@sql = sql
|
107
128
|
@binds = binds
|
108
129
|
end
|
@@ -169,9 +190,9 @@ module ActiveRecord
|
|
169
190
|
class RangeError < StatementInvalid
|
170
191
|
end
|
171
192
|
|
172
|
-
# Raised when number of
|
173
|
-
#
|
174
|
-
# does not match number of
|
193
|
+
# Raised when the number of placeholders in an SQL fragment passed to
|
194
|
+
# {ActiveRecord::Base.where}[rdoc-ref:QueryMethods#where]
|
195
|
+
# does not match the number of values supplied.
|
175
196
|
#
|
176
197
|
# For example, when there are two placeholders with only one value supplied:
|
177
198
|
#
|
@@ -183,6 +204,10 @@ module ActiveRecord
|
|
183
204
|
class NoDatabaseError < StatementInvalid
|
184
205
|
end
|
185
206
|
|
207
|
+
# Raised when creating a database if it exists.
|
208
|
+
class DatabaseAlreadyExists < StatementInvalid
|
209
|
+
end
|
210
|
+
|
186
211
|
# Raised when PostgreSQL returns 'cached plan must not change result type' and
|
187
212
|
# we cannot retry gracefully (e.g. inside a transaction)
|
188
213
|
class PreparedStatementCacheExpired < StatementInvalid
|
@@ -220,6 +245,10 @@ module ActiveRecord
|
|
220
245
|
class ReadOnlyRecord < ActiveRecordError
|
221
246
|
end
|
222
247
|
|
248
|
+
# Raised on attempt to lazily load records that are marked as strict loading.
|
249
|
+
class StrictLoadingViolationError < ActiveRecordError
|
250
|
+
end
|
251
|
+
|
223
252
|
# {ActiveRecord::Base.transaction}[rdoc-ref:Transactions::ClassMethods#transaction]
|
224
253
|
# uses this exception to distinguish a deliberate rollback from other exceptional situations.
|
225
254
|
# Normally, raising an exception will cause the
|
@@ -330,7 +359,7 @@ module ActiveRecord
|
|
330
359
|
# See the following:
|
331
360
|
#
|
332
361
|
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
333
|
-
# * https://dev.mysql.com/doc/
|
362
|
+
# * https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html#error_er_lock_deadlock
|
334
363
|
class TransactionRollbackError < StatementInvalid
|
335
364
|
end
|
336
365
|
|
@@ -349,30 +378,36 @@ module ActiveRecord
|
|
349
378
|
class IrreversibleOrderError < ActiveRecordError
|
350
379
|
end
|
351
380
|
|
381
|
+
# Superclass for errors that have been aborted (either by client or server).
|
382
|
+
class QueryAborted < StatementInvalid
|
383
|
+
end
|
384
|
+
|
352
385
|
# LockWaitTimeout will be raised when lock wait timeout exceeded.
|
353
386
|
class LockWaitTimeout < StatementInvalid
|
354
387
|
end
|
355
388
|
|
356
389
|
# StatementTimeout will be raised when statement timeout exceeded.
|
357
|
-
class StatementTimeout <
|
390
|
+
class StatementTimeout < QueryAborted
|
358
391
|
end
|
359
392
|
|
360
393
|
# QueryCanceled will be raised when canceling statement due to user request.
|
361
|
-
class QueryCanceled <
|
394
|
+
class QueryCanceled < QueryAborted
|
395
|
+
end
|
396
|
+
|
397
|
+
# AdapterTimeout will be raised when database clients times out while waiting from the server.
|
398
|
+
class AdapterTimeout < QueryAborted
|
362
399
|
end
|
363
400
|
|
364
401
|
# UnknownAttributeReference is raised when an unknown and potentially unsafe
|
365
|
-
# value is passed to a query method
|
366
|
-
#
|
367
|
-
# #order method might cause this exception.
|
402
|
+
# value is passed to a query method. For example, passing a non column name
|
403
|
+
# value to a relation's #order method might cause this exception.
|
368
404
|
#
|
369
405
|
# When working around this exception, caution should be taken to avoid SQL
|
370
406
|
# injection vulnerabilities when passing user-provided values to query
|
371
407
|
# methods. Known-safe values can be passed to query methods by wrapping them
|
372
408
|
# in Arel.sql.
|
373
409
|
#
|
374
|
-
# For example,
|
375
|
-
# code would raise this exception:
|
410
|
+
# For example, the following code would raise this exception:
|
376
411
|
#
|
377
412
|
# Post.order("length(title)").first
|
378
413
|
#
|
@@ -37,13 +37,18 @@ module ActiveRecord
|
|
37
37
|
|
38
38
|
private
|
39
39
|
def render_bind(attr)
|
40
|
-
|
41
|
-
|
40
|
+
if ActiveModel::Attribute === attr
|
41
|
+
value = if attr.type.binary? && attr.value
|
42
|
+
"<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
43
|
+
else
|
44
|
+
connection.type_cast(attr.value_for_database)
|
45
|
+
end
|
42
46
|
else
|
43
|
-
connection.type_cast(attr
|
47
|
+
value = connection.type_cast(attr)
|
48
|
+
attr = nil
|
44
49
|
end
|
45
50
|
|
46
|
-
[attr
|
51
|
+
[attr&.name, value]
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
payload[:exception] ||
|
27
27
|
payload[:cached] ||
|
28
28
|
IGNORED_PAYLOADS.include?(payload[:name]) ||
|
29
|
-
payload[:sql]
|
29
|
+
!payload[:sql].match?(EXPLAINED_SQLS)
|
30
30
|
end
|
31
31
|
|
32
32
|
ActiveSupport::Notifications.subscribe("sql.active_record", new)
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "yaml"
|
3
|
+
require "active_support/configuration_file"
|
5
4
|
|
6
5
|
module ActiveRecord
|
7
6
|
class FixtureSet
|
@@ -29,6 +28,10 @@ module ActiveRecord
|
|
29
28
|
config_row["model_class"]
|
30
29
|
end
|
31
30
|
|
31
|
+
def ignored_fixtures
|
32
|
+
config_row["ignore"]
|
33
|
+
end
|
34
|
+
|
32
35
|
private
|
33
36
|
def rows
|
34
37
|
@rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
|
@@ -40,31 +43,21 @@ module ActiveRecord
|
|
40
43
|
if row
|
41
44
|
row.last
|
42
45
|
else
|
43
|
-
{ 'model_class': nil }
|
46
|
+
{ 'model_class': nil, 'ignore': nil }
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
48
51
|
def raw_rows
|
49
52
|
@raw_rows ||= begin
|
50
|
-
data =
|
53
|
+
data = ActiveSupport::ConfigurationFile.parse(@file, context:
|
54
|
+
ActiveRecord::FixtureSet::RenderContext.create_subclass.new.get_binding)
|
51
55
|
data ? validate(data).to_a : []
|
52
|
-
rescue
|
53
|
-
raise Fixture::FormatError,
|
56
|
+
rescue RuntimeError => error
|
57
|
+
raise Fixture::FormatError, error.message
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
57
|
-
def prepare_erb(content)
|
58
|
-
erb = ERB.new(content)
|
59
|
-
erb.filename = @file
|
60
|
-
erb
|
61
|
-
end
|
62
|
-
|
63
|
-
def render(content)
|
64
|
-
context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
|
65
|
-
prepare_erb(content).result(context.get_binding)
|
66
|
-
end
|
67
|
-
|
68
61
|
# Validate our unmarshalled data.
|
69
62
|
def validate(data)
|
70
63
|
unless Hash === data || YAML::Omap === data
|
@@ -21,8 +21,7 @@ module ActiveRecord
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def timestamp_column_names
|
24
|
-
@
|
25
|
-
%w(created_at created_on updated_at updated_on) & @model_class.column_names
|
24
|
+
@model_class.all_timestamp_attributes_in_model
|
26
25
|
end
|
27
26
|
|
28
27
|
def inheritance_column_name
|
@@ -112,12 +112,12 @@ module ActiveRecord
|
|
112
112
|
case association.macro
|
113
113
|
when :belongs_to
|
114
114
|
# Do not replace association name with association foreign key if they are named the same
|
115
|
-
fk_name =
|
115
|
+
fk_name = association.join_foreign_key
|
116
116
|
|
117
117
|
if association.name.to_s != fk_name && value = @row.delete(association.name.to_s)
|
118
118
|
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
119
119
|
# support polymorphic belongs_to as "label (Type)"
|
120
|
-
@row[association.
|
120
|
+
@row[association.join_foreign_type] = $1
|
121
121
|
end
|
122
122
|
|
123
123
|
fk_type = reflection_class.type_for_attribute(fk_name).type
|
@@ -10,7 +10,6 @@ require "active_record/fixture_set/file"
|
|
10
10
|
require "active_record/fixture_set/render_context"
|
11
11
|
require "active_record/fixture_set/table_rows"
|
12
12
|
require "active_record/test_fixtures"
|
13
|
-
require "active_record/errors"
|
14
13
|
|
15
14
|
module ActiveRecord
|
16
15
|
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
@@ -41,7 +40,7 @@ module ActiveRecord
|
|
41
40
|
# separated by a blank line for your viewing pleasure.
|
42
41
|
#
|
43
42
|
# Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
|
44
|
-
# See
|
43
|
+
# See https://yaml.org/type/omap.html
|
45
44
|
# for the specification. You will need ordered fixtures when you have foreign key constraints
|
46
45
|
# on keys in the same table. This is commonly needed for tree structures. Example:
|
47
46
|
#
|
@@ -60,7 +59,7 @@ module ActiveRecord
|
|
60
59
|
# Since fixtures are a testing construct, we use them in our unit and functional tests. There
|
61
60
|
# are two ways to use the fixtures, but first let's take a look at a sample unit test:
|
62
61
|
#
|
63
|
-
# require
|
62
|
+
# require "test_helper"
|
64
63
|
#
|
65
64
|
# class WebSiteTest < ActiveSupport::TestCase
|
66
65
|
# test "web_site_count" do
|
@@ -182,7 +181,7 @@ module ActiveRecord
|
|
182
181
|
# end
|
183
182
|
# end
|
184
183
|
#
|
185
|
-
# If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
|
184
|
+
# If you preload your test database with all fixture data (probably by running `bin/rails db:fixtures:load`)
|
186
185
|
# and use transactional tests, then you may omit all fixtures declarations in your test cases since
|
187
186
|
# all the data's already there and every case rolls back its changes.
|
188
187
|
#
|
@@ -420,12 +419,35 @@ module ActiveRecord
|
|
420
419
|
#
|
421
420
|
# Any fixture labeled "DEFAULTS" is safely ignored.
|
422
421
|
#
|
422
|
+
# Besides using "DEFAULTS", you can also specify what fixtures will
|
423
|
+
# be ignored by setting "ignore" in "_fixture" section.
|
424
|
+
#
|
425
|
+
# # users.yml
|
426
|
+
# _fixture:
|
427
|
+
# ignore:
|
428
|
+
# - base
|
429
|
+
# # or use "ignore: base" when there is only one fixture needs to be ignored.
|
430
|
+
#
|
431
|
+
# base: &base
|
432
|
+
# admin: false
|
433
|
+
# introduction: "This is a default description"
|
434
|
+
#
|
435
|
+
# admin:
|
436
|
+
# <<: *base
|
437
|
+
# admin: true
|
438
|
+
#
|
439
|
+
# visitor:
|
440
|
+
# <<: *base
|
441
|
+
#
|
442
|
+
# In the above example, 'base' will be ignored when creating fixtures.
|
443
|
+
# This can be used for common attributes inheriting.
|
444
|
+
#
|
423
445
|
# == Configure the fixture model class
|
424
446
|
#
|
425
447
|
# It's possible to set the fixture's model class directly in the YAML file.
|
426
448
|
# This is helpful when fixtures are loaded outside tests and
|
427
449
|
# +set_fixture_class+ is not available (e.g.
|
428
|
-
# when running <tt>rails db:fixtures:load</tt>).
|
450
|
+
# when running <tt>bin/rails db:fixtures:load</tt>).
|
429
451
|
#
|
430
452
|
# _fixture:
|
431
453
|
# model_class: User
|
@@ -563,6 +585,14 @@ module ActiveRecord
|
|
563
585
|
end
|
564
586
|
end
|
565
587
|
|
588
|
+
def signed_global_id(fixture_set_name, label, column_type: :integer, **options)
|
589
|
+
identifier = identify(label, column_type)
|
590
|
+
model_name = default_fixture_model_name(fixture_set_name)
|
591
|
+
uri = URI::GID.build([GlobalID.app, model_name, identifier, {}])
|
592
|
+
|
593
|
+
SignedGlobalID.new(uri, **options)
|
594
|
+
end
|
595
|
+
|
566
596
|
# Superclass for the evaluation contexts used by ERB fixtures.
|
567
597
|
def context_class
|
568
598
|
@context_class ||= Class.new
|
@@ -619,7 +649,7 @@ module ActiveRecord
|
|
619
649
|
end
|
620
650
|
end
|
621
651
|
|
622
|
-
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
652
|
+
attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
|
623
653
|
|
624
654
|
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
|
625
655
|
@name = name
|
@@ -652,8 +682,8 @@ module ActiveRecord
|
|
652
682
|
# Returns a hash of rows to be inserted. The key is the table, the value is
|
653
683
|
# a list of rows to insert to that table.
|
654
684
|
def table_rows
|
655
|
-
# allow
|
656
|
-
fixtures.
|
685
|
+
# allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
|
686
|
+
fixtures.except!(*ignored_fixtures)
|
657
687
|
|
658
688
|
TableRows.new(
|
659
689
|
table_name,
|
@@ -672,6 +702,21 @@ module ActiveRecord
|
|
672
702
|
end
|
673
703
|
end
|
674
704
|
|
705
|
+
def ignored_fixtures=(base)
|
706
|
+
@ignored_fixtures =
|
707
|
+
case base
|
708
|
+
when Array
|
709
|
+
base
|
710
|
+
when String
|
711
|
+
[base]
|
712
|
+
else
|
713
|
+
[]
|
714
|
+
end
|
715
|
+
|
716
|
+
@ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
|
717
|
+
@ignored_fixtures.compact
|
718
|
+
end
|
719
|
+
|
675
720
|
# Loads the fixtures from the YAML file at +path+.
|
676
721
|
# If the file sets the +model_class+ and current instance value is not set,
|
677
722
|
# it uses the file value.
|
@@ -683,6 +728,7 @@ module ActiveRecord
|
|
683
728
|
yaml_files.each_with_object({}) do |file, fixtures|
|
684
729
|
FixtureSet::File.open(file) do |fh|
|
685
730
|
self.model_class ||= fh.model_class if fh.model_class
|
731
|
+
self.ignored_fixtures ||= fh.ignored_fixtures
|
686
732
|
fh.each do |fixture_name, row|
|
687
733
|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
688
734
|
end
|
@@ -38,6 +38,8 @@ module ActiveRecord
|
|
38
38
|
extend ActiveSupport::Concern
|
39
39
|
|
40
40
|
included do
|
41
|
+
class_attribute :store_full_class_name, instance_writer: false, default: true
|
42
|
+
|
41
43
|
# Determines whether to store the full constant name including namespace when using STI.
|
42
44
|
# This is true, by default.
|
43
45
|
class_attribute :store_full_sti_class, instance_writer: false, default: true
|
@@ -52,7 +54,7 @@ module ActiveRecord
|
|
52
54
|
raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
|
53
55
|
end
|
54
56
|
|
55
|
-
if
|
57
|
+
if _has_attribute?(inheritance_column)
|
56
58
|
subclass = subclass_from_attributes(attributes)
|
57
59
|
|
58
60
|
if subclass.nil? && scope_attributes = current_scope&.scope_for_create
|
@@ -162,12 +164,42 @@ module ActiveRecord
|
|
162
164
|
defined?(@abstract_class) && @abstract_class == true
|
163
165
|
end
|
164
166
|
|
167
|
+
# Returns the value to be stored in the inheritance column for STI.
|
165
168
|
def sti_name
|
166
|
-
store_full_sti_class ? name : name.demodulize
|
169
|
+
store_full_sti_class && store_full_class_name ? name : name.demodulize
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the class for the provided +type_name+.
|
173
|
+
#
|
174
|
+
# It is used to find the class correspondent to the value stored in the inheritance column.
|
175
|
+
def sti_class_for(type_name)
|
176
|
+
if store_full_sti_class && store_full_class_name
|
177
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
178
|
+
else
|
179
|
+
compute_type(type_name)
|
180
|
+
end
|
181
|
+
rescue NameError
|
182
|
+
raise SubclassNotFound,
|
183
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
184
|
+
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
185
|
+
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
186
|
+
"or overwrite #{name}.inheritance_column to use another column for that information."
|
167
187
|
end
|
168
188
|
|
189
|
+
# Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
|
169
190
|
def polymorphic_name
|
170
|
-
base_class.name
|
191
|
+
store_full_class_name ? base_class.name : base_class.name.demodulize
|
192
|
+
end
|
193
|
+
|
194
|
+
# Returns the class for the provided +name+.
|
195
|
+
#
|
196
|
+
# It is used to find the class correspondent to the value stored in the polymorphic type column.
|
197
|
+
def polymorphic_class_for(name)
|
198
|
+
if store_full_class_name
|
199
|
+
ActiveSupport::Dependencies.constantize(name)
|
200
|
+
else
|
201
|
+
compute_type(name)
|
202
|
+
end
|
171
203
|
end
|
172
204
|
|
173
205
|
def inherited(subclass)
|
@@ -219,32 +251,22 @@ module ActiveRecord
|
|
219
251
|
end
|
220
252
|
|
221
253
|
def using_single_table_inheritance?(record)
|
222
|
-
record[inheritance_column].present? &&
|
254
|
+
record[inheritance_column].present? && _has_attribute?(inheritance_column)
|
223
255
|
end
|
224
256
|
|
225
257
|
def find_sti_class(type_name)
|
226
258
|
type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
|
227
|
-
subclass =
|
228
|
-
|
229
|
-
ActiveSupport::Dependencies.constantize(type_name)
|
230
|
-
else
|
231
|
-
compute_type(type_name)
|
232
|
-
end
|
233
|
-
rescue NameError
|
234
|
-
raise SubclassNotFound,
|
235
|
-
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
236
|
-
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
237
|
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
238
|
-
"or overwrite #{name}.inheritance_column to use another column for that information."
|
239
|
-
end
|
259
|
+
subclass = sti_class_for(type_name)
|
260
|
+
|
240
261
|
unless subclass == self || descendants.include?(subclass)
|
241
262
|
raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
|
242
263
|
end
|
264
|
+
|
243
265
|
subclass
|
244
266
|
end
|
245
267
|
|
246
268
|
def type_condition(table = arel_table)
|
247
|
-
sti_column =
|
269
|
+
sti_column = table[inheritance_column]
|
248
270
|
sti_names = ([self] + descendants).map(&:sti_name)
|
249
271
|
|
250
272
|
predicate_builder.build(sti_column, sti_names)
|