activerecord 7.0.8.7 → 7.1.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1339 -1572
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +16 -11
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +12 -9
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +193 -97
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +128 -138
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +89 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +213 -109
- data/lib/active_record/model_schema.rb +47 -27
- data/lib/active_record/nested_attributes.rb +28 -3
- data/lib/active_record/normalization.rb +158 -0
- data/lib/active_record/persistence.rb +183 -33
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +169 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +85 -15
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +41 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +52 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -6,7 +6,6 @@ require "active_record/relation/merger"
|
|
6
6
|
|
7
7
|
module ActiveRecord
|
8
8
|
module SpawnMethods
|
9
|
-
# This is overridden by Associations::CollectionProxy
|
10
9
|
def spawn # :nodoc:
|
11
10
|
already_in_scope?(klass.scope_registry) ? klass.all : clone
|
12
11
|
end
|
@@ -28,6 +27,9 @@ module ActiveRecord
|
|
28
27
|
# # => Post.where(published: true).joins(:comments)
|
29
28
|
#
|
30
29
|
# This is mainly intended for sharing common conditions between multiple associations.
|
30
|
+
#
|
31
|
+
# For conditions that exist in both relations, those from <tt>other</tt> will take precedence.
|
32
|
+
# To find the intersection of two relations, use QueryMethods#and.
|
31
33
|
def merge(other, *rest)
|
32
34
|
if other.is_a?(Array)
|
33
35
|
records & other
|
@@ -40,6 +42,21 @@ module ActiveRecord
|
|
40
42
|
|
41
43
|
def merge!(other, *rest) # :nodoc:
|
42
44
|
options = rest.extract_options!
|
45
|
+
|
46
|
+
if options.key?(:rewhere)
|
47
|
+
if options[:rewhere]
|
48
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
49
|
+
Specifying `Relation#merge(rewhere: true)` is deprecated, as that has now been
|
50
|
+
the default since Rails 7.0. Setting the rewhere option will error in Rails 7.2
|
51
|
+
MSG
|
52
|
+
else
|
53
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
54
|
+
`Relation#merge(rewhere: false)` is deprecated without replacement,
|
55
|
+
and will be removed in Rails 7.2
|
56
|
+
MSG
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
43
60
|
if other.is_a?(Hash)
|
44
61
|
Relation::HashMerger.new(self, other, options[:rewhere]).merge
|
45
62
|
elsif other.is_a?(Relation)
|
@@ -5,13 +5,14 @@ module ActiveRecord
|
|
5
5
|
class Relation
|
6
6
|
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
|
7
7
|
:order, :joins, :left_outer_joins, :references,
|
8
|
-
:extending, :unscope, :optimizer_hints, :annotate
|
8
|
+
:extending, :unscope, :optimizer_hints, :annotate,
|
9
|
+
:with]
|
9
10
|
|
10
11
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
|
11
12
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
13
|
|
13
14
|
CLAUSE_METHODS = [:where, :having, :from]
|
14
|
-
INVALID_METHODS_FOR_DELETE_ALL = [:distinct]
|
15
|
+
INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with]
|
15
16
|
|
16
17
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
17
18
|
|
@@ -33,6 +34,8 @@ module ActiveRecord
|
|
33
34
|
@delegate_to_klass = false
|
34
35
|
@future_result = nil
|
35
36
|
@records = nil
|
37
|
+
@async = false
|
38
|
+
@none = false
|
36
39
|
end
|
37
40
|
|
38
41
|
def initialize_copy(other)
|
@@ -43,7 +46,7 @@ module ActiveRecord
|
|
43
46
|
def bind_attribute(name, value) # :nodoc:
|
44
47
|
if reflection = klass._reflect_on_association(name)
|
45
48
|
name = reflection.foreign_key
|
46
|
-
value = value.read_attribute(reflection.
|
49
|
+
value = value.read_attribute(reflection.association_primary_key) unless value.nil?
|
47
50
|
end
|
48
51
|
|
49
52
|
attr = table[name]
|
@@ -159,21 +162,25 @@ module ActiveRecord
|
|
159
162
|
# failed due to validation errors it won't be persisted, you get what
|
160
163
|
# #create returns in such situation.
|
161
164
|
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
165
|
+
# If creation failed because of a unique constraint, this method will
|
166
|
+
# assume it encountered a race condition and will try finding the record
|
167
|
+
# once more If somehow the second find still find no record because a
|
168
|
+
# concurrent DELETE happened, it will then raise an
|
169
|
+
# ActiveRecord::RecordNotFound exception.
|
166
170
|
#
|
167
|
-
#
|
171
|
+
# Please note <b>this method is not atomic</b>, it runs first a SELECT,
|
172
|
+
# and if there are no results an INSERT is attempted. So if the table
|
173
|
+
# doesn't have a relevant unique constraint it could be the case that
|
174
|
+
# you end up with two or more similar records.
|
168
175
|
def find_or_create_by(attributes, &block)
|
169
|
-
find_by(attributes) ||
|
176
|
+
find_by(attributes) || create_or_find_by(attributes, &block)
|
170
177
|
end
|
171
178
|
|
172
179
|
# Like #find_or_create_by, but calls
|
173
180
|
# {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
|
174
181
|
# is raised if the created record is invalid.
|
175
182
|
def find_or_create_by!(attributes, &block)
|
176
|
-
find_by(attributes) ||
|
183
|
+
find_by(attributes) || create_or_find_by!(attributes, &block)
|
177
184
|
end
|
178
185
|
|
179
186
|
# Attempts to create a record with the given attributes in a table that has a unique database constraint
|
@@ -181,16 +188,15 @@ module ActiveRecord
|
|
181
188
|
# unique constraints, the exception such an insertion would normally raise is caught,
|
182
189
|
# and the existing record with those attributes is found using #find_by!.
|
183
190
|
#
|
184
|
-
# This is similar to #find_or_create_by, but
|
185
|
-
#
|
186
|
-
# if none is found.
|
191
|
+
# This is similar to #find_or_create_by, but tries to create the record first. As such it is
|
192
|
+
# better suited for cases where the record is most likely not to exist yet.
|
187
193
|
#
|
188
194
|
# There are several drawbacks to #create_or_find_by, though:
|
189
195
|
#
|
190
196
|
# * The underlying table must have the relevant columns defined with unique database constraints.
|
191
197
|
# * A unique constraint violation may be triggered by only one, or at least less than all,
|
192
198
|
# of the given attributes. This means that the subsequent #find_by! may fail to find a
|
193
|
-
# matching record, which will then raise an
|
199
|
+
# matching record, which will then raise an ActiveRecord::RecordNotFound exception,
|
194
200
|
# rather than a record with the given attributes.
|
195
201
|
# * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by,
|
196
202
|
# we actually have another race condition between INSERT -> SELECT, which can be triggered
|
@@ -199,7 +205,7 @@ module ActiveRecord
|
|
199
205
|
# * It relies on exception handling to handle control flow, which may be marginally slower.
|
200
206
|
# * The primary key may auto-increment on each create, even if it fails. This can accelerate
|
201
207
|
# the problem of running out of integers, if the underlying table is still stuck on a primary
|
202
|
-
# key of type int (note: All Rails apps since 5.1+ have defaulted to bigint, which is not liable
|
208
|
+
# key of type int (note: All \Rails apps since 5.1+ have defaulted to bigint, which is not liable
|
203
209
|
# to this problem).
|
204
210
|
#
|
205
211
|
# This method will return a record if all given attributes are covered by unique constraints
|
@@ -209,7 +215,11 @@ module ActiveRecord
|
|
209
215
|
def create_or_find_by(attributes, &block)
|
210
216
|
transaction(requires_new: true) { create(attributes, &block) }
|
211
217
|
rescue ActiveRecord::RecordNotUnique
|
212
|
-
|
218
|
+
if connection.transaction_open?
|
219
|
+
where(attributes).lock.find_by!(attributes)
|
220
|
+
else
|
221
|
+
find_by!(attributes)
|
222
|
+
end
|
213
223
|
end
|
214
224
|
|
215
225
|
# Like #create_or_find_by, but calls
|
@@ -218,7 +228,11 @@ module ActiveRecord
|
|
218
228
|
def create_or_find_by!(attributes, &block)
|
219
229
|
transaction(requires_new: true) { create!(attributes, &block) }
|
220
230
|
rescue ActiveRecord::RecordNotUnique
|
221
|
-
|
231
|
+
if connection.transaction_open?
|
232
|
+
where(attributes).lock.find_by!(attributes)
|
233
|
+
else
|
234
|
+
find_by!(attributes)
|
235
|
+
end
|
222
236
|
end
|
223
237
|
|
224
238
|
# Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
|
@@ -236,8 +250,8 @@ module ActiveRecord
|
|
236
250
|
#
|
237
251
|
# Please see further details in the
|
238
252
|
# {Active Record Query Interface guide}[https://guides.rubyonrails.org/active_record_querying.html#running-explain].
|
239
|
-
def explain
|
240
|
-
exec_explain(collecting_queries_for_explain { exec_queries })
|
253
|
+
def explain(*options)
|
254
|
+
exec_explain(collecting_queries_for_explain { exec_queries }, options)
|
241
255
|
end
|
242
256
|
|
243
257
|
# Converts relation objects to Array.
|
@@ -267,6 +281,8 @@ module ActiveRecord
|
|
267
281
|
|
268
282
|
# Returns true if there are no records.
|
269
283
|
def empty?
|
284
|
+
return true if @none
|
285
|
+
|
270
286
|
if loaded?
|
271
287
|
records.empty?
|
272
288
|
else
|
@@ -275,26 +291,34 @@ module ActiveRecord
|
|
275
291
|
end
|
276
292
|
|
277
293
|
# Returns true if there are no records.
|
278
|
-
def none?
|
279
|
-
return
|
294
|
+
def none?(*args)
|
295
|
+
return true if @none
|
296
|
+
|
297
|
+
return super if args.present? || block_given?
|
280
298
|
empty?
|
281
299
|
end
|
282
300
|
|
283
301
|
# Returns true if there are any records.
|
284
|
-
def any?
|
285
|
-
return
|
302
|
+
def any?(*args)
|
303
|
+
return false if @none
|
304
|
+
|
305
|
+
return super if args.present? || block_given?
|
286
306
|
!empty?
|
287
307
|
end
|
288
308
|
|
289
309
|
# Returns true if there is exactly one record.
|
290
|
-
def one?
|
291
|
-
return
|
310
|
+
def one?(*args)
|
311
|
+
return false if @none
|
312
|
+
|
313
|
+
return super if args.present? || block_given?
|
292
314
|
return records.one? if loaded?
|
293
315
|
limited_count == 1
|
294
316
|
end
|
295
317
|
|
296
318
|
# Returns true if there is more than one record.
|
297
319
|
def many?
|
320
|
+
return false if @none
|
321
|
+
|
298
322
|
return super if block_given?
|
299
323
|
return records.many? if loaded?
|
300
324
|
limited_count > 1
|
@@ -307,7 +331,7 @@ module ActiveRecord
|
|
307
331
|
# # => "products/query-1850ab3d302391b85b8693e941286659"
|
308
332
|
#
|
309
333
|
# If ActiveRecord::Base.collection_cache_versioning is turned off, as it was
|
310
|
-
# in Rails 6.0 and earlier, the cache key will also include a version.
|
334
|
+
# in \Rails 6.0 and earlier, the cache key will also include a version.
|
311
335
|
#
|
312
336
|
# ActiveRecord::Base.collection_cache_versioning = false
|
313
337
|
# Product.where("name like ?", "%Cosmic Encounter%").cache_key
|
@@ -409,7 +433,7 @@ module ActiveRecord
|
|
409
433
|
# Comment.where(post_id: 1).scoping do
|
410
434
|
# Comment.first
|
411
435
|
# end
|
412
|
-
# #
|
436
|
+
# # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
413
437
|
#
|
414
438
|
# If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
|
415
439
|
# for the relation including +update+ and +delete+ on instances.
|
@@ -446,7 +470,8 @@ module ActiveRecord
|
|
446
470
|
#
|
447
471
|
# ==== Parameters
|
448
472
|
#
|
449
|
-
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
|
473
|
+
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement. Any strings provided will
|
474
|
+
# be type cast, unless you use +Arel.sql+. (Don't pass user-provided values to +Arel.sql+.)
|
450
475
|
#
|
451
476
|
# ==== Examples
|
452
477
|
#
|
@@ -461,9 +486,14 @@ module ActiveRecord
|
|
461
486
|
#
|
462
487
|
# # Update all invoices and set the number column to its id value.
|
463
488
|
# Invoice.update_all('number = id')
|
489
|
+
#
|
490
|
+
# # Update all books with 'Rails' in their title
|
491
|
+
# Book.where('title LIKE ?', '%Rails%').update_all(title: Arel.sql("title + ' - volume 1'"))
|
464
492
|
def update_all(updates)
|
465
493
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
466
494
|
|
495
|
+
return 0 if @none
|
496
|
+
|
467
497
|
if updates.is_a?(Hash)
|
468
498
|
if klass.locking_enabled? &&
|
469
499
|
!updates.key?(klass.locking_column) &&
|
@@ -599,6 +629,8 @@ module ActiveRecord
|
|
599
629
|
# Post.distinct.delete_all
|
600
630
|
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
|
601
631
|
def delete_all
|
632
|
+
return 0 if @none
|
633
|
+
|
602
634
|
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
|
603
635
|
value = @values[method]
|
604
636
|
method == :distinct ? value : value&.any?
|
@@ -720,7 +752,7 @@ module ActiveRecord
|
|
720
752
|
# Returns sql statement for the relation.
|
721
753
|
#
|
722
754
|
# User.where(name: 'Oscar').to_sql
|
723
|
-
# #
|
755
|
+
# # SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
724
756
|
def to_sql
|
725
757
|
@to_sql ||= if eager_loading?
|
726
758
|
apply_join_dependency do |relation, join_dependency|
|
@@ -774,8 +806,13 @@ module ActiveRecord
|
|
774
806
|
end
|
775
807
|
end
|
776
808
|
|
777
|
-
def pretty_print(
|
778
|
-
|
809
|
+
def pretty_print(pp)
|
810
|
+
subject = loaded? ? records : annotate("loading for pp")
|
811
|
+
entries = subject.take([limit_value, 11].compact.min)
|
812
|
+
|
813
|
+
entries[10] = "..." if entries.size == 11
|
814
|
+
|
815
|
+
pp.pp(entries)
|
779
816
|
end
|
780
817
|
|
781
818
|
# Returns true if relation is blank.
|
@@ -837,10 +874,6 @@ module ActiveRecord
|
|
837
874
|
@loaded = true
|
838
875
|
end
|
839
876
|
|
840
|
-
def null_relation? # :nodoc:
|
841
|
-
is_a?(NullRelation)
|
842
|
-
end
|
843
|
-
|
844
877
|
private
|
845
878
|
def already_in_scope?(registry)
|
846
879
|
@delegate_to_klass && registry.current_scope(klass, true)
|
@@ -925,6 +958,14 @@ module ActiveRecord
|
|
925
958
|
end
|
926
959
|
|
927
960
|
def exec_main_query(async: false)
|
961
|
+
if @none
|
962
|
+
if async
|
963
|
+
return Promise::Complete.new([])
|
964
|
+
else
|
965
|
+
return []
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
928
969
|
skip_query_cache_if_necessary do
|
929
970
|
if where_clause.contradiction?
|
930
971
|
[].freeze
|
data/lib/active_record/result.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
###
|
5
|
+
# = Active Record \Result
|
6
|
+
#
|
5
7
|
# This class encapsulates a result returned from calling
|
6
8
|
# {#exec_query}[rdoc-ref:ConnectionAdapters::DatabaseStatements#exec_query]
|
7
9
|
# on any database connection adapter. For example:
|
@@ -36,8 +38,12 @@ module ActiveRecord
|
|
36
38
|
|
37
39
|
attr_reader :columns, :rows, :column_types
|
38
40
|
|
39
|
-
def self.empty # :nodoc:
|
40
|
-
|
41
|
+
def self.empty(async: false) # :nodoc:
|
42
|
+
if async
|
43
|
+
EMPTY_ASYNC
|
44
|
+
else
|
45
|
+
EMPTY
|
46
|
+
end
|
41
47
|
end
|
42
48
|
|
43
49
|
def initialize(columns, rows, column_types = {})
|
@@ -47,9 +53,6 @@ module ActiveRecord
|
|
47
53
|
@column_types = column_types
|
48
54
|
end
|
49
55
|
|
50
|
-
EMPTY = new([].freeze, [].freeze, {}.freeze)
|
51
|
-
private_constant :EMPTY
|
52
|
-
|
53
56
|
# Returns true if this result set includes the column named +name+
|
54
57
|
def includes_column?(name)
|
55
58
|
@columns.include? name
|
@@ -134,6 +137,11 @@ module ActiveRecord
|
|
134
137
|
@hash_rows = nil
|
135
138
|
end
|
136
139
|
|
140
|
+
def freeze # :nodoc:
|
141
|
+
hash_rows.freeze
|
142
|
+
super
|
143
|
+
end
|
144
|
+
|
137
145
|
private
|
138
146
|
def column_type(name, index, type_overrides)
|
139
147
|
type_overrides.fetch(name) do
|
@@ -183,5 +191,11 @@ module ActiveRecord
|
|
183
191
|
}
|
184
192
|
end
|
185
193
|
end
|
194
|
+
|
195
|
+
EMPTY = new([].freeze, [].freeze, {}.freeze).freeze
|
196
|
+
private_constant :EMPTY
|
197
|
+
|
198
|
+
EMPTY_ASYNC = FutureResult::Complete.new(EMPTY).freeze
|
199
|
+
private_constant :EMPTY_ASYNC
|
186
200
|
end
|
187
201
|
end
|
@@ -10,11 +10,20 @@ module ActiveRecord
|
|
10
10
|
extend self
|
11
11
|
|
12
12
|
def sql_runtime
|
13
|
-
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime]
|
13
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] ||= 0.0
|
14
14
|
end
|
15
15
|
|
16
16
|
def sql_runtime=(runtime)
|
17
17
|
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
|
18
18
|
end
|
19
|
+
|
20
|
+
def reset
|
21
|
+
rt, self.sql_runtime = sql_runtime, 0.0
|
22
|
+
rt
|
23
|
+
end
|
19
24
|
end
|
20
25
|
end
|
26
|
+
|
27
|
+
ActiveSupport::Notifications.monotonic_subscribe("sql.active_record") do |name, start, finish, id, payload|
|
28
|
+
ActiveRecord::RuntimeRegistry.sql_runtime += (finish - start) * 1_000.0
|
29
|
+
end
|
@@ -5,8 +5,8 @@ module ActiveRecord
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
# Accepts an array
|
9
|
-
#
|
8
|
+
# Accepts an array of SQL conditions and sanitizes them into a valid
|
9
|
+
# SQL fragment for a WHERE clause.
|
10
10
|
#
|
11
11
|
# sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
|
12
12
|
# # => "name='foo''bar' and group_id=4"
|
@@ -17,8 +17,19 @@ module ActiveRecord
|
|
17
17
|
# sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
|
18
18
|
# # => "name='foo''bar' and group_id='4'"
|
19
19
|
#
|
20
|
+
# This method will NOT sanitize a SQL string since it won't contain
|
21
|
+
# any conditions in it and will return the string as is.
|
22
|
+
#
|
20
23
|
# sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
|
21
24
|
# # => "name='foo''bar' and group_id='4'"
|
25
|
+
#
|
26
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
27
|
+
# and will directly use the database adapter's +quote+ method.
|
28
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
29
|
+
# to prevent query manipulation attacks.
|
30
|
+
#
|
31
|
+
# sanitize_sql_for_conditions(["role = ?", 0])
|
32
|
+
# # => "role = '0'"
|
22
33
|
def sanitize_sql_for_conditions(condition)
|
23
34
|
return nil if condition.blank?
|
24
35
|
|
@@ -29,8 +40,8 @@ module ActiveRecord
|
|
29
40
|
end
|
30
41
|
alias :sanitize_sql :sanitize_sql_for_conditions
|
31
42
|
|
32
|
-
# Accepts an array
|
33
|
-
#
|
43
|
+
# Accepts an array or hash of SQL conditions and sanitizes them into
|
44
|
+
# a valid SQL fragment for a SET clause.
|
34
45
|
#
|
35
46
|
# sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
|
36
47
|
# # => "name=NULL and group_id=4"
|
@@ -41,8 +52,19 @@ module ActiveRecord
|
|
41
52
|
# Post.sanitize_sql_for_assignment({ name: nil, group_id: 4 })
|
42
53
|
# # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
|
43
54
|
#
|
55
|
+
# This method will NOT sanitize a SQL string since it won't contain
|
56
|
+
# any conditions in it and will return the string as is.
|
57
|
+
#
|
44
58
|
# sanitize_sql_for_assignment("name=NULL and group_id='4'")
|
45
59
|
# # => "name=NULL and group_id='4'"
|
60
|
+
#
|
61
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
62
|
+
# and will directly use the database adapter's +quote+ method.
|
63
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
64
|
+
# to prevent query manipulation attacks.
|
65
|
+
#
|
66
|
+
# sanitize_sql_for_assignment(["role = ?", 0])
|
67
|
+
# # => "role = '0'"
|
46
68
|
def sanitize_sql_for_assignment(assignments, default_table_name = table_name)
|
47
69
|
case assignments
|
48
70
|
when Array; sanitize_sql_array(assignments)
|
@@ -107,12 +129,17 @@ module ActiveRecord
|
|
107
129
|
# sanitize_sql_like("snake_cased_string", "!")
|
108
130
|
# # => "snake!_cased!_string"
|
109
131
|
def sanitize_sql_like(string, escape_character = "\\")
|
110
|
-
|
111
|
-
|
132
|
+
if string.include?(escape_character) && escape_character != "%" && escape_character != "_"
|
133
|
+
string = string.gsub(escape_character, '\0\0')
|
134
|
+
end
|
135
|
+
|
136
|
+
string.gsub(/(?=[%_])/, escape_character)
|
112
137
|
end
|
113
138
|
|
114
139
|
# Accepts an array of conditions. The array has each value
|
115
|
-
# sanitized and interpolated into the SQL statement.
|
140
|
+
# sanitized and interpolated into the SQL statement. If using named bind
|
141
|
+
# variables in SQL statements where a colon is required verbatim use a
|
142
|
+
# backslash to escape.
|
116
143
|
#
|
117
144
|
# sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
|
118
145
|
# # => "name='foo''bar' and group_id=4"
|
@@ -120,8 +147,19 @@ module ActiveRecord
|
|
120
147
|
# sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
121
148
|
# # => "name='foo''bar' and group_id=4"
|
122
149
|
#
|
150
|
+
# sanitize_sql_array(["TO_TIMESTAMP(:date, 'YYYY/MM/DD HH12\\:MI\\:SS')", date: "foo"])
|
151
|
+
# # => "TO_TIMESTAMP('foo', 'YYYY/MM/DD HH12:MI:SS')"
|
152
|
+
#
|
123
153
|
# sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
|
124
154
|
# # => "name='foo''bar' and group_id='4'"
|
155
|
+
#
|
156
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
157
|
+
# and will directly use the database adapter's +quote+ method.
|
158
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
159
|
+
# to prevent query manipulation attacks.
|
160
|
+
#
|
161
|
+
# sanitize_sql_array(["role = ?", 0])
|
162
|
+
# # => "role = '0'"
|
125
163
|
def sanitize_sql_array(ary)
|
126
164
|
statement, *values = ary
|
127
165
|
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
@@ -173,9 +211,11 @@ module ActiveRecord
|
|
173
211
|
end
|
174
212
|
|
175
213
|
def replace_named_bind_variables(statement, bind_vars)
|
176
|
-
statement.gsub(/(
|
214
|
+
statement.gsub(/([:\\]?):([a-zA-Z]\w*)/) do |match|
|
177
215
|
if $1 == ":" # skip postgresql casts
|
178
216
|
match # return the whole match
|
217
|
+
elsif $1 == "\\" # escaped literal colon
|
218
|
+
match[1..-1] # return match with escaping backlash char removed
|
179
219
|
elsif bind_vars.include?(match = $2.to_sym)
|
180
220
|
replace_bind_variable(bind_vars[match])
|
181
221
|
else
|
@@ -188,13 +228,13 @@ module ActiveRecord
|
|
188
228
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
189
229
|
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
190
230
|
if values.empty?
|
191
|
-
c.
|
231
|
+
c.quote(c.cast_bound_value(nil))
|
192
232
|
else
|
193
|
-
values.map! { |v| c.
|
233
|
+
values.map! { |v| c.quote(c.cast_bound_value(v)) }.join(",")
|
194
234
|
end
|
195
235
|
else
|
196
236
|
value = value.id_for_database if value.respond_to?(:id_for_database)
|
197
|
-
c.
|
237
|
+
c.quote(c.cast_bound_value(value))
|
198
238
|
end
|
199
239
|
end
|
200
240
|
|
data/lib/active_record/schema.rb
CHANGED
@@ -54,13 +54,12 @@ module ActiveRecord
|
|
54
54
|
def define(info, &block) # :nodoc:
|
55
55
|
instance_eval(&block)
|
56
56
|
|
57
|
+
connection.schema_migration.create_table
|
57
58
|
if info[:version].present?
|
58
|
-
connection.schema_migration.create_table
|
59
59
|
connection.assume_migrated_upto_version(info[:version])
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
|
62
|
+
connection.internal_metadata.create_table_and_set_flags(connection.migration_context.current_environment)
|
64
63
|
end
|
65
64
|
end
|
66
65
|
|
@@ -13,8 +13,7 @@ module ActiveRecord
|
|
13
13
|
##
|
14
14
|
# :singleton-method:
|
15
15
|
# A list of tables which should not be dumped to the schema.
|
16
|
-
# Acceptable values are strings
|
17
|
-
# Only strings are accepted if ActiveRecord.schema_format == :sql.
|
16
|
+
# Acceptable values are strings and regexps.
|
18
17
|
cattr_accessor :ignore_tables, default: []
|
19
18
|
|
20
19
|
##
|
@@ -29,6 +28,18 @@ module ActiveRecord
|
|
29
28
|
# should not be dumped to db/schema.rb.
|
30
29
|
cattr_accessor :chk_ignore_pattern, default: /^chk_rails_[0-9a-f]{10}$/
|
31
30
|
|
31
|
+
##
|
32
|
+
# :singleton-method:
|
33
|
+
# Specify a custom regular expression matching exclusion constraints which name
|
34
|
+
# should not be dumped to db/schema.rb.
|
35
|
+
cattr_accessor :excl_ignore_pattern, default: /^excl_rails_[0-9a-f]{10}$/
|
36
|
+
|
37
|
+
##
|
38
|
+
# :singleton-method:
|
39
|
+
# Specify a custom regular expression matching unique constraints which name
|
40
|
+
# should not be dumped to db/schema.rb.
|
41
|
+
cattr_accessor :unique_ignore_pattern, default: /^uniq_rails_[0-9a-f]{10}$/
|
42
|
+
|
32
43
|
class << self
|
33
44
|
def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
|
34
45
|
connection.create_schema_dumper(generate_options(config)).dump(stream)
|
@@ -60,6 +71,11 @@ module ActiveRecord
|
|
60
71
|
@connection = connection
|
61
72
|
@version = connection.migration_context.current_version rescue nil
|
62
73
|
@options = options
|
74
|
+
@ignore_tables = [
|
75
|
+
ActiveRecord::Base.schema_migrations_table_name,
|
76
|
+
ActiveRecord::Base.internal_metadata_table_name,
|
77
|
+
self.class.ignore_tables
|
78
|
+
].flatten
|
63
79
|
end
|
64
80
|
|
65
81
|
# turns 20170404131909 into "2017_04_04_131909"
|
@@ -111,7 +127,7 @@ module ActiveRecord
|
|
111
127
|
end
|
112
128
|
|
113
129
|
# dump foreign keys at the end to make sure all dependent tables exist.
|
114
|
-
if @connection.
|
130
|
+
if @connection.use_foreign_keys?
|
115
131
|
sorted_tables.each do |tbl|
|
116
132
|
foreign_keys(tbl, stream) unless ignored?(tbl)
|
117
133
|
end
|
@@ -171,12 +187,13 @@ module ActiveRecord
|
|
171
187
|
|
172
188
|
indexes_in_create(table, tbl)
|
173
189
|
check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
|
190
|
+
exclusion_constraints_in_create(table, tbl) if @connection.supports_exclusion_constraints?
|
191
|
+
unique_keys_in_create(table, tbl) if @connection.supports_unique_keys?
|
174
192
|
|
175
193
|
tbl.puts " end"
|
176
194
|
tbl.puts
|
177
195
|
|
178
|
-
tbl.
|
179
|
-
stream.print tbl.read
|
196
|
+
stream.print tbl.string
|
180
197
|
rescue => e
|
181
198
|
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
182
199
|
stream.puts "# #{e.message}"
|
@@ -201,6 +218,18 @@ module ActiveRecord
|
|
201
218
|
|
202
219
|
def indexes_in_create(table, stream)
|
203
220
|
if (indexes = @connection.indexes(table)).any?
|
221
|
+
if @connection.supports_exclusion_constraints? && (exclusion_constraints = @connection.exclusion_constraints(table)).any?
|
222
|
+
exclusion_constraint_names = exclusion_constraints.collect(&:name)
|
223
|
+
|
224
|
+
indexes = indexes.reject { |index| exclusion_constraint_names.include?(index.name) }
|
225
|
+
end
|
226
|
+
|
227
|
+
if @connection.supports_unique_keys? && (unique_keys = @connection.unique_keys(table)).any?
|
228
|
+
unique_key_names = unique_keys.collect(&:name)
|
229
|
+
|
230
|
+
indexes = indexes.reject { |index| unique_key_names.include?(index.name) }
|
231
|
+
end
|
232
|
+
|
204
233
|
index_statements = indexes.map do |index|
|
205
234
|
" t.index #{index_parts(index).join(', ')}"
|
206
235
|
end
|
@@ -219,6 +248,8 @@ module ActiveRecord
|
|
219
248
|
index_parts << "opclass: #{format_index_parts(index.opclasses)}" if index.opclasses.present?
|
220
249
|
index_parts << "where: #{index.where.inspect}" if index.where
|
221
250
|
index_parts << "using: #{index.using.inspect}" if !@connection.default_index_type?(index)
|
251
|
+
index_parts << "include: #{index.include.inspect}" if index.include
|
252
|
+
index_parts << "nulls_not_distinct: #{index.nulls_not_distinct.inspect}" if index.nulls_not_distinct
|
222
253
|
index_parts << "type: #{index.type.inspect}" if index.type
|
223
254
|
index_parts << "comment: #{index.comment.inspect}" if index.comment
|
224
255
|
index_parts
|
@@ -235,6 +266,8 @@ module ActiveRecord
|
|
235
266
|
parts << "name: #{check_constraint.name.inspect}"
|
236
267
|
end
|
237
268
|
|
269
|
+
parts << "validate: #{check_constraint.validate?.inspect}" unless check_constraint.validate?
|
270
|
+
|
238
271
|
" #{parts.join(', ')}"
|
239
272
|
end
|
240
273
|
|
@@ -250,7 +283,7 @@ module ActiveRecord
|
|
250
283
|
remove_prefix_and_suffix(foreign_key.to_table).inspect,
|
251
284
|
]
|
252
285
|
|
253
|
-
if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
|
286
|
+
if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table, "id")
|
254
287
|
parts << "column: #{foreign_key.column.inspect}"
|
255
288
|
end
|
256
289
|
|
@@ -265,6 +298,7 @@ module ActiveRecord
|
|
265
298
|
parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
|
266
299
|
parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
|
267
300
|
parts << "deferrable: #{foreign_key.deferrable.inspect}" if foreign_key.deferrable
|
301
|
+
parts << "validate: #{foreign_key.validate?.inspect}" unless foreign_key.validate?
|
268
302
|
|
269
303
|
" #{parts.join(', ')}"
|
270
304
|
end
|
@@ -302,7 +336,7 @@ module ActiveRecord
|
|
302
336
|
end
|
303
337
|
|
304
338
|
def ignored?(table_name)
|
305
|
-
|
339
|
+
@ignore_tables.any? do |ignored|
|
306
340
|
ignored === remove_prefix_and_suffix(table_name)
|
307
341
|
end
|
308
342
|
end
|