activerecord 7.0.2.4 → 7.0.4
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 +172 -0
- data/lib/active_record/associations/collection_association.rb +1 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +7 -4
- data/lib/active_record/associations/join_dependency.rb +17 -13
- data/lib/active_record/associations.rb +15 -15
- data/lib/active_record/attribute_methods/serialization.rb +34 -50
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attribute_methods.rb +1 -1
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/coders/yaml_column.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +3 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +19 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +7 -2
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +3 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/encryption/configurable.rb +8 -2
- data/lib/active_record/encryption/contexts.rb +3 -3
- data/lib/active_record/encryption/derived_secret_key_provider.rb +1 -1
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +2 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encryptor.rb +7 -7
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -4
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/properties.rb +1 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +1 -1
- data/lib/active_record/fixtures.rb +4 -4
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +10 -5
- data/lib/active_record/middleware/database_selector.rb +13 -6
- data/lib/active_record/middleware/shard_selector.rb +4 -4
- data/lib/active_record/migration/command_recorder.rb +3 -3
- data/lib/active_record/migration/compatibility.rb +7 -26
- data/lib/active_record/migration.rb +5 -4
- data/lib/active_record/model_schema.rb +22 -10
- data/lib/active_record/persistence.rb +9 -8
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +20 -16
- data/lib/active_record/railties/databases.rake +16 -11
- data/lib/active_record/reflection.rb +6 -0
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +27 -6
- data/lib/active_record/relation.rb +7 -6
- data/lib/active_record/sanitization.rb +6 -5
- data/lib/active_record/scoping/default.rb +5 -7
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +2 -2
- data/lib/active_record/store.rb +7 -2
- data/lib/active_record/tasks/database_tasks.rb +26 -21
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -2
- data/lib/active_record/test_fixtures.rb +12 -5
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/validations/associated.rb +3 -3
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +3 -3
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +14 -0
- metadata +10 -10
@@ -7,11 +7,11 @@ module ActiveRecord
|
|
7
7
|
# shard to switch to and allows for applications to write custom strategies
|
8
8
|
# for swapping if needed.
|
9
9
|
#
|
10
|
-
# The ShardSelector takes a set of options (currently only
|
11
|
-
# that can be used by the middleware to alter behavior.
|
10
|
+
# The ShardSelector takes a set of options (currently only +lock+ is supported)
|
11
|
+
# that can be used by the middleware to alter behavior. +lock+ is
|
12
12
|
# true by default and will prohibit the request from switching shards once
|
13
|
-
# inside the block. If
|
14
|
-
# For tenant based sharding,
|
13
|
+
# inside the block. If +lock+ is false, then shard swapping will be allowed.
|
14
|
+
# For tenant based sharding, +lock+ should always be true to prevent application
|
15
15
|
# code from mistakenly switching between tenants.
|
16
16
|
#
|
17
17
|
# Options can be set in the config:
|
@@ -13,10 +13,10 @@ module ActiveRecord
|
|
13
13
|
# * add_reference
|
14
14
|
# * add_timestamps
|
15
15
|
# * change_column
|
16
|
-
# * change_column_default (must supply a
|
16
|
+
# * change_column_default (must supply a +:from+ and +:to+ option)
|
17
17
|
# * change_column_null
|
18
|
-
# * change_column_comment (must supply a
|
19
|
-
# * change_table_comment (must supply a
|
18
|
+
# * change_column_comment (must supply a +:from+ and +:to+ option)
|
19
|
+
# * change_table_comment (must supply a +:from+ and +:to+ option)
|
20
20
|
# * create_join_table
|
21
21
|
# * create_table
|
22
22
|
# * disable_extension
|
@@ -92,27 +92,10 @@ module ActiveRecord
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
module SQLite3
|
96
|
-
module TableDefinition
|
97
|
-
def references(*args, **options)
|
98
|
-
args.each do |ref_name|
|
99
|
-
ReferenceDefinition.new(ref_name, type: :integer, **options).add_to(self)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
alias :belongs_to :references
|
103
|
-
|
104
|
-
def column(name, type, index: nil, **options)
|
105
|
-
options[:precision] ||= nil
|
106
|
-
super
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
95
|
module TableDefinition
|
112
96
|
def references(*args, **options)
|
113
|
-
|
114
|
-
|
115
|
-
end
|
97
|
+
options[:_uses_legacy_reference_index_name] = true
|
98
|
+
super
|
116
99
|
end
|
117
100
|
alias :belongs_to :references
|
118
101
|
|
@@ -148,12 +131,11 @@ module ActiveRecord
|
|
148
131
|
|
149
132
|
def add_reference(table_name, ref_name, **options)
|
150
133
|
if connection.adapter_name == "SQLite"
|
151
|
-
|
152
|
-
else
|
153
|
-
reference_definition = ReferenceDefinition.new(ref_name, **options)
|
134
|
+
options[:type] = :integer
|
154
135
|
end
|
155
136
|
|
156
|
-
|
137
|
+
options[:_uses_legacy_reference_index_name] = true
|
138
|
+
super
|
157
139
|
end
|
158
140
|
alias :add_belongs_to :add_reference
|
159
141
|
|
@@ -161,9 +143,8 @@ module ActiveRecord
|
|
161
143
|
def compatible_table_definition(t)
|
162
144
|
class << t
|
163
145
|
prepend TableDefinition
|
164
|
-
prepend SQLite3::TableDefinition
|
165
146
|
end
|
166
|
-
|
147
|
+
super
|
167
148
|
end
|
168
149
|
end
|
169
150
|
|
@@ -228,7 +209,7 @@ module ActiveRecord
|
|
228
209
|
class << t
|
229
210
|
prepend TableDefinition
|
230
211
|
end
|
231
|
-
|
212
|
+
super
|
232
213
|
end
|
233
214
|
|
234
215
|
def command_recorder
|
@@ -326,7 +326,7 @@ module ActiveRecord
|
|
326
326
|
# details.
|
327
327
|
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
328
328
|
# the table called +name+. It makes the table object available to a block that
|
329
|
-
# can then add/remove columns, indexes or foreign keys to it.
|
329
|
+
# can then add/remove columns, indexes, or foreign keys to it.
|
330
330
|
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
331
331
|
# a column but keeps the type and content.
|
332
332
|
# * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
|
@@ -576,7 +576,7 @@ module ActiveRecord
|
|
576
576
|
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
577
577
|
|
578
578
|
# This class is used to verify that all migrations have been run before
|
579
|
-
# loading a web page if <tt>config.active_record.migration_error</tt> is set to
|
579
|
+
# loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
|
580
580
|
class CheckPending
|
581
581
|
def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
|
582
582
|
@app = app
|
@@ -810,8 +810,9 @@ module ActiveRecord
|
|
810
810
|
|
811
811
|
# Runs the given migration classes.
|
812
812
|
# Last argument can specify options:
|
813
|
-
#
|
814
|
-
# -
|
813
|
+
#
|
814
|
+
# - +:direction+ - Default is +:up+.
|
815
|
+
# - +:revert+ - Default is +false+.
|
815
816
|
def run(*migration_classes)
|
816
817
|
opts = migration_classes.extract_options!
|
817
818
|
dir = opts[:direction] || :up
|
@@ -126,6 +126,27 @@ module ActiveRecord
|
|
126
126
|
# +:immutable_string+. This setting does not affect the behavior of
|
127
127
|
# <tt>attribute :foo, :string</tt>. Defaults to false.
|
128
128
|
|
129
|
+
##
|
130
|
+
# :singleton-method: inheritance_column
|
131
|
+
# :call-seq: inheritance_column
|
132
|
+
#
|
133
|
+
# The name of the table column which stores the class name on single-table
|
134
|
+
# inheritance situations.
|
135
|
+
#
|
136
|
+
# The default inheritance column name is +type+, which means it's a
|
137
|
+
# reserved word inside Active Record. To be able to use single-table
|
138
|
+
# inheritance with another column name, or to use the column +type+ in
|
139
|
+
# your own model for something else, you can set +inheritance_column+:
|
140
|
+
#
|
141
|
+
# self.inheritance_column = 'zoink'
|
142
|
+
|
143
|
+
##
|
144
|
+
# :singleton-method: inheritance_column=
|
145
|
+
# :call-seq: inheritance_column=(column)
|
146
|
+
#
|
147
|
+
# Defines the name of the table column which will store the class name on single-table
|
148
|
+
# inheritance situations.
|
149
|
+
|
129
150
|
included do
|
130
151
|
class_attribute :primary_key_prefix_type, instance_writer: false
|
131
152
|
class_attribute :table_name_prefix, instance_writer: false, default: ""
|
@@ -136,15 +157,6 @@ module ActiveRecord
|
|
136
157
|
class_attribute :implicit_order_column, instance_accessor: false
|
137
158
|
class_attribute :immutable_strings_by_default, instance_accessor: false
|
138
159
|
|
139
|
-
# Defines the name of the table column which will store the class name on single-table
|
140
|
-
# inheritance situations.
|
141
|
-
#
|
142
|
-
# The default inheritance column name is +type+, which means it's a
|
143
|
-
# reserved word inside Active Record. To be able to use single-table
|
144
|
-
# inheritance with another column name, or to use the column +type+ in
|
145
|
-
# your own model for something else, you can set +inheritance_column+:
|
146
|
-
#
|
147
|
-
# self.inheritance_column = 'zoink'
|
148
160
|
class_attribute :inheritance_column, instance_accessor: false, default: "type"
|
149
161
|
singleton_class.class_eval do
|
150
162
|
alias_method :_inheritance_column=, :inheritance_column=
|
@@ -617,7 +629,7 @@ module ActiveRecord
|
|
617
629
|
|
618
630
|
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
|
619
631
|
else
|
620
|
-
# STI subclasses always use their superclass' table.
|
632
|
+
# STI subclasses always use their superclass's table.
|
621
633
|
base_class.table_name
|
622
634
|
end
|
623
635
|
end
|
@@ -62,7 +62,7 @@ module ActiveRecord
|
|
62
62
|
# Active Record callbacks or validations. Though passed values
|
63
63
|
# go through Active Record's type casting and serialization.
|
64
64
|
#
|
65
|
-
# See
|
65
|
+
# See #insert_all for documentation.
|
66
66
|
def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
|
67
67
|
insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
68
68
|
end
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
79
79
|
# duplicate rows are skipped.
|
80
80
|
# Override with <tt>:unique_by</tt> (see below).
|
81
81
|
#
|
82
|
-
# Returns an
|
82
|
+
# Returns an ActiveRecord::Result with its contents based on
|
83
83
|
# <tt>:returning</tt> (see below).
|
84
84
|
#
|
85
85
|
# ==== Options
|
@@ -151,7 +151,7 @@ module ActiveRecord
|
|
151
151
|
# Active Record callbacks or validations. Though passed values
|
152
152
|
# go through Active Record's type casting and serialization.
|
153
153
|
#
|
154
|
-
# See
|
154
|
+
# See #insert_all! for more.
|
155
155
|
def insert!(attributes, returning: nil, record_timestamps: nil)
|
156
156
|
insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
|
157
157
|
end
|
@@ -167,10 +167,9 @@ module ActiveRecord
|
|
167
167
|
# Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
|
168
168
|
# unique index on the table. In that case, no rows are inserted.
|
169
169
|
#
|
170
|
-
# To skip duplicate rows, see
|
171
|
-
# To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
|
170
|
+
# To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
|
172
171
|
#
|
173
|
-
# Returns an
|
172
|
+
# Returns an ActiveRecord::Result with its contents based on
|
174
173
|
# <tt>:returning</tt> (see below).
|
175
174
|
#
|
176
175
|
# ==== Options
|
@@ -219,7 +218,7 @@ module ActiveRecord
|
|
219
218
|
# it trigger Active Record callbacks or validations. Though passed values
|
220
219
|
# go through Active Record's type casting and serialization.
|
221
220
|
#
|
222
|
-
# See
|
221
|
+
# See #upsert_all for documentation.
|
223
222
|
def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil, record_timestamps: nil)
|
224
223
|
upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
225
224
|
end
|
@@ -232,7 +231,7 @@ module ActiveRecord
|
|
232
231
|
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
233
232
|
# the attributes for a single row and must have the same keys.
|
234
233
|
#
|
235
|
-
# Returns an
|
234
|
+
# Returns an ActiveRecord::Result with its contents based on
|
236
235
|
# <tt>:returning</tt> (see below).
|
237
236
|
#
|
238
237
|
# By default, +upsert_all+ will update all the columns that can be updated when
|
@@ -806,6 +805,7 @@ module ActiveRecord
|
|
806
805
|
def update_columns(attributes)
|
807
806
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
808
807
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
808
|
+
_raise_readonly_record_error if readonly?
|
809
809
|
|
810
810
|
attributes = attributes.transform_keys do |key|
|
811
811
|
name = key.to_s
|
@@ -992,6 +992,7 @@ module ActiveRecord
|
|
992
992
|
#
|
993
993
|
def touch(*names, time: nil)
|
994
994
|
_raise_record_not_touched_error unless persisted?
|
995
|
+
_raise_readonly_record_error if readonly?
|
995
996
|
|
996
997
|
attribute_names = timestamp_attributes_for_update_in_model
|
997
998
|
attribute_names |= names.map! do |name|
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
39
39
|
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
40
40
|
# # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "author"=>"Quentin"}>, ...]
|
41
41
|
#
|
42
|
-
# You can use the same string replacement techniques as you can with
|
42
|
+
# You can use the same string replacement techniques as you can with ActiveRecord::QueryMethods#where :
|
43
43
|
#
|
44
44
|
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
45
45
|
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
|
@@ -78,6 +78,12 @@ module ActiveRecord
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
+
initializer "active_record.postgresql_time_zone_aware_types" do
|
82
|
+
ActiveSupport.on_load(:active_record_postgresqladapter) do
|
83
|
+
ActiveRecord::Base.time_zone_aware_types << :timestamptz
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
81
87
|
initializer "active_record.logger" do
|
82
88
|
ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
|
83
89
|
end
|
@@ -94,22 +100,6 @@ module ActiveRecord
|
|
94
100
|
end
|
95
101
|
end
|
96
102
|
|
97
|
-
initializer "active_record.database_selector" do
|
98
|
-
if options = config.active_record.database_selector
|
99
|
-
resolver = config.active_record.database_resolver
|
100
|
-
operations = config.active_record.database_resolver_context
|
101
|
-
config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
initializer "active_record.shard_selector" do
|
106
|
-
if resolver = config.active_record.shard_resolver
|
107
|
-
options = config.active_record.shard_selector || {}
|
108
|
-
|
109
|
-
config.app_middleware.use ActiveRecord::Middleware::ShardSelector, resolver, options
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
103
|
initializer "Check for cache versioning support" do
|
114
104
|
config.after_initialize do |app|
|
115
105
|
ActiveSupport.on_load(:active_record) do
|
@@ -389,5 +379,19 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
389
379
|
end
|
390
380
|
end
|
391
381
|
end
|
382
|
+
|
383
|
+
initializer "active_record.unregister_current_scopes_on_unload" do |app|
|
384
|
+
config.after_initialize do
|
385
|
+
unless app.config.cache_classes
|
386
|
+
Rails.autoloaders.main.on_unload do |_cpath, value, _abspath|
|
387
|
+
# Conditions are written this way to be robust against custom
|
388
|
+
# implementations of value#is_a? or value#<.
|
389
|
+
if Class === value && ActiveRecord::Base > value
|
390
|
+
value.current_scope = nil
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
392
396
|
end
|
393
397
|
end
|
@@ -452,30 +452,32 @@ db_namespace = namespace :db do
|
|
452
452
|
end
|
453
453
|
|
454
454
|
namespace :schema do
|
455
|
-
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`)"
|
455
|
+
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
|
456
456
|
task dump: :load_config do
|
457
457
|
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
458
458
|
if db_config.schema_dump
|
459
459
|
ActiveRecord::Base.establish_connection(db_config)
|
460
|
-
ActiveRecord
|
460
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
461
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
|
461
462
|
end
|
462
463
|
end
|
463
464
|
|
464
465
|
db_namespace["schema:dump"].reenable
|
465
466
|
end
|
466
467
|
|
467
|
-
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the database"
|
468
|
+
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the database"
|
468
469
|
task load: [:load_config, :check_protected_environments] do
|
469
470
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord.schema_format, ENV["SCHEMA"])
|
470
471
|
end
|
471
472
|
|
472
473
|
namespace :dump do
|
473
474
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
474
|
-
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for #{name} database"
|
475
|
+
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) for #{name} database"
|
475
476
|
task name => :load_config do
|
476
477
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
|
477
478
|
ActiveRecord::Base.establish_connection(db_config)
|
478
|
-
ActiveRecord
|
479
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
480
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
|
479
481
|
db_namespace["schema:dump:#{name}"].reenable
|
480
482
|
end
|
481
483
|
end
|
@@ -483,11 +485,12 @@ db_namespace = namespace :db do
|
|
483
485
|
|
484
486
|
namespace :load do
|
485
487
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
486
|
-
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the #{name} database"
|
487
|
-
task name => :load_config do
|
488
|
+
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the #{name} database"
|
489
|
+
task name => [:load_config, :check_protected_environments] do
|
488
490
|
original_db_config = ActiveRecord::Base.connection_db_config
|
489
491
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
|
490
|
-
ActiveRecord
|
492
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
493
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
|
491
494
|
ensure
|
492
495
|
ActiveRecord::Base.establish_connection(original_db_config) if original_db_config
|
493
496
|
end
|
@@ -545,12 +548,13 @@ db_namespace = namespace :db do
|
|
545
548
|
db_namespace["test:load_schema"].invoke
|
546
549
|
end
|
547
550
|
|
548
|
-
# desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `config.active_record.schema_format`)"
|
551
|
+
# desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
|
549
552
|
task load_schema: %w(db:test:purge) do
|
550
553
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
551
554
|
ActiveRecord::Schema.verbose = false
|
552
555
|
ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
|
553
|
-
ActiveRecord
|
556
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
557
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
|
554
558
|
end
|
555
559
|
ensure
|
556
560
|
if should_reconnect
|
@@ -586,7 +590,8 @@ db_namespace = namespace :db do
|
|
586
590
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
587
591
|
ActiveRecord::Schema.verbose = false
|
588
592
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "test", name: name)
|
589
|
-
ActiveRecord
|
593
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
594
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
|
590
595
|
ensure
|
591
596
|
if should_reconnect
|
592
597
|
ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
|
@@ -297,6 +297,12 @@ module ActiveRecord
|
|
297
297
|
options[:strict_loading]
|
298
298
|
end
|
299
299
|
|
300
|
+
def strict_loading_violation_message(owner)
|
301
|
+
message = +"`#{owner}` is marked for strict_loading."
|
302
|
+
message << " The #{polymorphic? ? "polymorphic association" : "#{klass} association"}"
|
303
|
+
message << " named `:#{name}` cannot be lazily loaded."
|
304
|
+
end
|
305
|
+
|
300
306
|
protected
|
301
307
|
def actual_source_reflection # FIXME: this is a horrible name
|
302
308
|
self
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
38
38
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
39
39
|
# an order is present in the relation.
|
40
|
-
# * <tt>:order</tt> - Specifies the primary key order (can be
|
40
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+). Defaults to +:asc+.
|
41
41
|
#
|
42
42
|
# Limits are honored, and if present there is no requirement for the batch
|
43
43
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -102,7 +102,7 @@ module ActiveRecord
|
|
102
102
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
103
103
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
104
104
|
# an order is present in the relation.
|
105
|
-
# * <tt>:order</tt> - Specifies the primary key order (can be
|
105
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+). Defaults to +:asc+.
|
106
106
|
#
|
107
107
|
# Limits are honored, and if present there is no requirement for the batch
|
108
108
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -167,7 +167,7 @@ module ActiveRecord
|
|
167
167
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
168
168
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
169
169
|
# an order is present in the relation.
|
170
|
-
# * <tt>:order</tt> - Specifies the primary key order (can be
|
170
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+). Defaults to +:asc+.
|
171
171
|
#
|
172
172
|
# Limits are honored, and if present there is no requirement for the batch
|
173
173
|
# size, it can be less than, equal, or greater than the limit.
|
@@ -10,10 +10,10 @@ module ActiveRecord
|
|
10
10
|
module QueryMethods
|
11
11
|
include ActiveModel::ForbiddenAttributesProtection
|
12
12
|
|
13
|
-
# WhereChain objects act as placeholder for queries in which
|
14
|
-
# In this case,
|
13
|
+
# WhereChain objects act as placeholder for queries in which +where+ does not have any parameter.
|
14
|
+
# In this case, +where+ can be chained to return a new relation.
|
15
15
|
class WhereChain
|
16
|
-
def initialize(scope)
|
16
|
+
def initialize(scope) # :nodoc:
|
17
17
|
@scope = scope
|
18
18
|
end
|
19
19
|
|
@@ -40,6 +40,13 @@ module ActiveRecord
|
|
40
40
|
#
|
41
41
|
# User.where.not(name: "Jon", role: "admin")
|
42
42
|
# # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
|
43
|
+
#
|
44
|
+
# If there is a non-nil condition on a nullable column in the hash condition, the records that have
|
45
|
+
# nil values on the nullable column won't be returned.
|
46
|
+
# User.create!(nullable_country: nil)
|
47
|
+
# User.where.not(nullable_country: "UK")
|
48
|
+
# # SELECT * FROM users WHERE NOT (nullable_country = 'UK')
|
49
|
+
# # => []
|
43
50
|
def not(opts, *rest)
|
44
51
|
where_clause = @scope.send(:build_where_clause, opts, rest)
|
45
52
|
|
@@ -162,7 +169,7 @@ module ActiveRecord
|
|
162
169
|
#
|
163
170
|
# users = User.includes(:address, friends: [:address, :followers])
|
164
171
|
#
|
165
|
-
# ===
|
172
|
+
# === Conditions
|
166
173
|
#
|
167
174
|
# If you want to add string conditions to your included models, you'll have
|
168
175
|
# to explicitly reference them. For example:
|
@@ -710,12 +717,26 @@ module ActiveRecord
|
|
710
717
|
# === no argument
|
711
718
|
#
|
712
719
|
# If no argument is passed, #where returns a new instance of WhereChain, that
|
713
|
-
# can be chained with #not
|
720
|
+
# can be chained with WhereChain#not, WhereChain#missing, or WhereChain#associated.
|
721
|
+
#
|
722
|
+
# Chaining with WhereChain#not:
|
714
723
|
#
|
715
724
|
# User.where.not(name: "Jon")
|
716
725
|
# # SELECT * FROM users WHERE name != 'Jon'
|
717
726
|
#
|
718
|
-
#
|
727
|
+
# Chaining with WhereChain#associated:
|
728
|
+
#
|
729
|
+
# Post.where.associated(:author)
|
730
|
+
# # SELECT "posts".* FROM "posts"
|
731
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
732
|
+
# # WHERE "authors"."id" IS NOT NULL
|
733
|
+
#
|
734
|
+
# Chaining with WhereChain#missing:
|
735
|
+
#
|
736
|
+
# Post.where.missing(:author)
|
737
|
+
# # SELECT "posts".* FROM "posts"
|
738
|
+
# # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
739
|
+
# # WHERE "authors"."id" IS NULL
|
719
740
|
#
|
720
741
|
# === blank condition
|
721
742
|
#
|
@@ -429,10 +429,10 @@ module ActiveRecord
|
|
429
429
|
end
|
430
430
|
end
|
431
431
|
|
432
|
-
def _exec_scope(
|
432
|
+
def _exec_scope(...) # :nodoc:
|
433
433
|
@delegate_to_klass = true
|
434
434
|
registry = klass.scope_registry
|
435
|
-
_scoping(nil, registry) { instance_exec(
|
435
|
+
_scoping(nil, registry) { instance_exec(...) || self }
|
436
436
|
ensure
|
437
437
|
@delegate_to_klass = false
|
438
438
|
end
|
@@ -654,7 +654,7 @@ module ActiveRecord
|
|
654
654
|
# for queries to actually be executed concurrently. Otherwise it defaults to
|
655
655
|
# executing them in the foreground.
|
656
656
|
#
|
657
|
-
# +load_async+ will also
|
657
|
+
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
658
658
|
# fixtures are enabled.
|
659
659
|
#
|
660
660
|
# If the query was actually executed in the background, the Active Record logs will show
|
@@ -712,6 +712,7 @@ module ActiveRecord
|
|
712
712
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
713
713
|
@offsets = @take = nil
|
714
714
|
@cache_keys = nil
|
715
|
+
@cache_versions = nil
|
715
716
|
@records = nil
|
716
717
|
self
|
717
718
|
end
|
@@ -736,7 +737,7 @@ module ActiveRecord
|
|
736
737
|
#
|
737
738
|
# User.where(name: 'Oscar').where_values_hash
|
738
739
|
# # => {name: "Oscar"}
|
739
|
-
def where_values_hash(relation_table_name = klass.table_name)
|
740
|
+
def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
|
740
741
|
where_clause.to_h(relation_table_name)
|
741
742
|
end
|
742
743
|
|
@@ -756,7 +757,7 @@ module ActiveRecord
|
|
756
757
|
# Joins that are also marked for preloading. In which case we should just eager load them.
|
757
758
|
# Note that this is a naive implementation because we could have strings and symbols which
|
758
759
|
# represent the same association, but that aren't matched by this. Also, we could have
|
759
|
-
# nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] }
|
760
|
+
# nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
|
760
761
|
def joined_includes_values
|
761
762
|
includes_values & joins_values
|
762
763
|
end
|
@@ -917,7 +918,7 @@ module ActiveRecord
|
|
917
918
|
preload_associations(records) unless skip_preloading_value
|
918
919
|
|
919
920
|
records.each(&:readonly!) if readonly_value
|
920
|
-
records.each
|
921
|
+
records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
|
921
922
|
|
922
923
|
records
|
923
924
|
end
|
@@ -92,16 +92,17 @@ module ActiveRecord
|
|
92
92
|
end
|
93
93
|
|
94
94
|
# Sanitizes a +string+ so that it is safe to use within an SQL
|
95
|
-
# LIKE statement. This method uses +escape_character+ to escape all
|
95
|
+
# LIKE statement. This method uses +escape_character+ to escape all
|
96
|
+
# occurrences of itself, "_" and "%".
|
96
97
|
#
|
97
|
-
# sanitize_sql_like("100%")
|
98
|
-
# # => "100\\%"
|
98
|
+
# sanitize_sql_like("100% true!")
|
99
|
+
# # => "100\\% true!"
|
99
100
|
#
|
100
101
|
# sanitize_sql_like("snake_cased_string")
|
101
102
|
# # => "snake\\_cased\\_string"
|
102
103
|
#
|
103
|
-
# sanitize_sql_like("100%", "!")
|
104
|
-
# # => "100!%"
|
104
|
+
# sanitize_sql_like("100% true!", "!")
|
105
|
+
# # => "100!% true!!"
|
105
106
|
#
|
106
107
|
# sanitize_sql_like("snake_cased_string", "!")
|
107
108
|
# # => "snake!_cased!_string"
|
@@ -48,10 +48,6 @@ module ActiveRecord
|
|
48
48
|
super || default_scopes.any? || respond_to?(:default_scope)
|
49
49
|
end
|
50
50
|
|
51
|
-
def before_remove_const # :nodoc:
|
52
|
-
self.current_scope = nil
|
53
|
-
end
|
54
|
-
|
55
51
|
# Checks if the model has any default scopes. If all_queries
|
56
52
|
# is set to true, the method will check if there are any
|
57
53
|
# default_scopes for the model where +all_queries+ is true.
|
@@ -83,7 +79,7 @@ module ActiveRecord
|
|
83
79
|
# <tt>all_queries: true</tt>:
|
84
80
|
#
|
85
81
|
# class Article < ActiveRecord::Base
|
86
|
-
# default_scope { where(blog_id: 1) }, all_queries: true
|
82
|
+
# default_scope -> { where(blog_id: 1) }, all_queries: true
|
87
83
|
# end
|
88
84
|
#
|
89
85
|
# Applying a default scope to all queries will ensure that records
|
@@ -150,11 +146,13 @@ module ActiveRecord
|
|
150
146
|
end
|
151
147
|
elsif default_scopes.any?
|
152
148
|
evaluate_default_scope do
|
153
|
-
default_scopes.inject(relation) do |
|
149
|
+
default_scopes.inject(relation) do |combined_scope, scope_obj|
|
154
150
|
if execute_scope?(all_queries, scope_obj)
|
155
151
|
scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
|
156
152
|
|
157
|
-
|
153
|
+
combined_scope.instance_exec(&scope) || combined_scope
|
154
|
+
else
|
155
|
+
combined_scope
|
158
156
|
end
|
159
157
|
end
|
160
158
|
end
|
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# Works like
|
50
|
+
# Works like find_signed, but will raise an +ActiveSupport::MessageVerifier::InvalidSignature+
|
51
51
|
# exception if the +signed_id+ has either expired, has a purpose mismatch, is for another record,
|
52
52
|
# or has been tampered with. It will also raise an +ActiveRecord::RecordNotFound+ exception if
|
53
53
|
# the valid signed id can't find a record.
|
@@ -97,7 +97,7 @@ module ActiveRecord
|
|
97
97
|
|
98
98
|
# Returns a signed id that's generated using a preconfigured +ActiveSupport::MessageVerifier+ instance.
|
99
99
|
# This signed id is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
|
100
|
-
# It can
|
100
|
+
# It can furthermore be set to expire (the default is not to expire), and scoped down with a specific purpose.
|
101
101
|
# If the expiration date has been exceeded before +find_signed+ is called, the id won't find the designated
|
102
102
|
# record. If a purpose is set, this too must match.
|
103
103
|
#
|