activerecord 7.0.2.2 → 7.0.3
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 +57 -0
- data/lib/active_record/associations/collection_association.rb +1 -1
- data/lib/active_record/associations/collection_proxy.rb +1 -1
- data/lib/active_record/associations.rb +9 -9
- data/lib/active_record/attribute_methods/serialization.rb +34 -50
- data/lib/active_record/attribute_methods.rb +1 -1
- data/lib/active_record/base.rb +3 -3
- 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 +4 -0
- 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/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +1 -1
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +3 -3
- 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/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 +1 -1
- data/lib/active_record/persistence.rb +9 -8
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +14 -0
- data/lib/active_record/railties/databases.rake +1 -1
- 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 +8 -1
- data/lib/active_record/relation.rb +6 -6
- data/lib/active_record/sanitization.rb +6 -5
- data/lib/active_record/scoping/default.rb +1 -5
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +1 -1
- 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 +3 -0
- 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
- metadata +10 -10
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Encryption
|
5
|
-
# An
|
5
|
+
# An ActiveModel::Type::Value that encrypts/decrypts strings of text.
|
6
6
|
#
|
7
7
|
# This is the central piece that connects the encryption system with +encrypts+ declarations in the
|
8
8
|
# model classes. Whenever you declare an attribute as encrypted, it configures an +EncryptedAttributeType+
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
#
|
20
20
|
# * <tt>:scheme</tt> - A +Scheme+ with the encryption properties for this attribute.
|
21
21
|
# * <tt>:cast_type</tt> - A type that will be used to serialize (before encrypting) and deserialize
|
22
|
-
# (after decrypting).
|
22
|
+
# (after decrypting). ActiveModel::Type::String by default.
|
23
23
|
def initialize(scheme:, cast_type: ActiveModel::Type::String.new, previous_type: false)
|
24
24
|
super()
|
25
25
|
@scheme = scheme
|
@@ -6,17 +6,17 @@ require "active_support/core_ext/numeric"
|
|
6
6
|
|
7
7
|
module ActiveRecord
|
8
8
|
module Encryption
|
9
|
-
# An encryptor exposes the encryption API that
|
9
|
+
# An encryptor exposes the encryption API that ActiveRecord::Encryption::EncryptedAttributeType
|
10
10
|
# uses for encrypting and decrypting attribute values.
|
11
11
|
#
|
12
|
-
# It interacts with a
|
13
|
-
#
|
12
|
+
# It interacts with a KeyProvider for getting the keys, and delegate to
|
13
|
+
# ActiveRecord::Encryption::Cipher the actual encryption algorithm.
|
14
14
|
class Encryptor
|
15
15
|
# Encrypts +clean_text+ and returns the encrypted result
|
16
16
|
#
|
17
17
|
# Internally, it will:
|
18
18
|
#
|
19
|
-
# 1. Create a new
|
19
|
+
# 1. Create a new ActiveRecord::Encryption::Message
|
20
20
|
# 2. Compress and encrypt +clean_text+ as the message payload
|
21
21
|
# 3. Serialize it with +ActiveRecord::Encryption.message_serializer+ (+ActiveRecord::Encryption::SafeMarshal+
|
22
22
|
# by default)
|
@@ -26,10 +26,10 @@ module ActiveRecord
|
|
26
26
|
#
|
27
27
|
# [:key_provider]
|
28
28
|
# Key provider to use for the encryption operation. It will default to
|
29
|
-
# +ActiveRecord::Encryption.key_provider+ when not provided
|
29
|
+
# +ActiveRecord::Encryption.key_provider+ when not provided.
|
30
30
|
#
|
31
31
|
# [:cipher_options]
|
32
|
-
#
|
32
|
+
# Cipher-specific options that will be passed to the Cipher configured in
|
33
33
|
# +ActiveRecord::Encryption.cipher+
|
34
34
|
def encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
|
35
35
|
clear_text = force_encoding_if_needed(clear_text) if cipher_options[:deterministic]
|
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
47
47
|
# +ActiveRecord::Encryption.key_provider+ when not provided
|
48
48
|
#
|
49
49
|
# [:cipher_options]
|
50
|
-
#
|
50
|
+
# Cipher-specific options that will be passed to the Cipher configured in
|
51
51
|
# +ActiveRecord::Encryption.cipher+
|
52
52
|
def decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
|
53
53
|
message = deserialize_message(encrypted_text)
|
@@ -4,13 +4,13 @@ module ActiveRecord
|
|
4
4
|
module Encryption
|
5
5
|
# Implements a simple envelope encryption approach where:
|
6
6
|
#
|
7
|
-
# * It generates a random data-encryption key for each encryption operation
|
7
|
+
# * It generates a random data-encryption key for each encryption operation.
|
8
8
|
# * It stores the generated key along with the encrypted payload. It encrypts this key
|
9
|
-
# with the master key provided in the
|
9
|
+
# with the master key provided in the +active_record_encryption.primary_key+ credential.
|
10
10
|
#
|
11
11
|
# This provider can work with multiple master keys. It will use the last one for encrypting.
|
12
12
|
#
|
13
|
-
# When
|
13
|
+
# When +config.active_record.encryption.store_key_references+ is true, it will also store a reference to
|
14
14
|
# the specific master key that was used to encrypt the data-encryption key. When not set,
|
15
15
|
# it will try all the configured master keys looking for the right one, in order to
|
16
16
|
# return the right decryption key.
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
module Encryption
|
5
5
|
# Automatically expand encrypted arguments to support querying both encrypted and unencrypted data
|
6
6
|
#
|
7
|
-
# Active Record Encryption supports querying the db using deterministic attributes. For example:
|
7
|
+
# Active Record \Encryption supports querying the db using deterministic attributes. For example:
|
8
8
|
#
|
9
9
|
# Contact.find_by(email_address: "jorge@hey.com")
|
10
10
|
#
|
@@ -16,10 +16,10 @@ module ActiveRecord
|
|
16
16
|
#
|
17
17
|
# This patches ActiveRecord to support this automatically. It addresses both:
|
18
18
|
#
|
19
|
-
# * ActiveRecord::Base
|
20
|
-
# * ActiveRecord::Relation
|
19
|
+
# * ActiveRecord::Base - Used in <tt>Contact.find_by_email_address(...)</tt>
|
20
|
+
# * ActiveRecord::Relation - Used in <tt>Contact.internal.find_by_email_address(...)</tt>
|
21
21
|
#
|
22
|
-
#
|
22
|
+
# ActiveRecord::Base relies on ActiveRecord::Relation (ActiveRecord::QueryMethods) but it does
|
23
23
|
# some prepared statements caching. That's why we need to intercept +ActiveRecord::Base+ as soon
|
24
24
|
# as it's invoked (so that the proper prepared statement is cached).
|
25
25
|
#
|
data/lib/active_record/enum.rb
CHANGED
@@ -83,7 +83,7 @@ module ActiveRecord
|
|
83
83
|
#
|
84
84
|
# In rare circumstances you might need to access the mapping directly.
|
85
85
|
# The mappings are exposed through a class method with the pluralized attribute
|
86
|
-
# name, which return the mapping in a
|
86
|
+
# name, which return the mapping in a ActiveSupport::HashWithIndifferentAccess :
|
87
87
|
#
|
88
88
|
# Conversation.statuses[:active] # => 0
|
89
89
|
# Conversation.statuses["archived"] # => 1
|
@@ -241,13 +241,13 @@ module ActiveRecord
|
|
241
241
|
# The generated ID for a given label is constant, so we can discover
|
242
242
|
# any fixture's ID without loading anything, as long as we know the label.
|
243
243
|
#
|
244
|
-
# == Label references for associations (belongs_to
|
244
|
+
# == Label references for associations (+belongs_to+, +has_one+, +has_many+)
|
245
245
|
#
|
246
246
|
# Specifying foreign keys in fixtures can be very fragile, not to
|
247
247
|
# mention difficult to read. Since Active Record can figure out the ID of
|
248
248
|
# any fixture from its label, you can specify FK's by label instead of ID.
|
249
249
|
#
|
250
|
-
# === belongs_to
|
250
|
+
# === +belongs_to+
|
251
251
|
#
|
252
252
|
# Let's break out some more monkeys and pirates.
|
253
253
|
#
|
@@ -286,7 +286,7 @@ module ActiveRecord
|
|
286
286
|
# a target *label* for the *association* (monkey: george) rather than
|
287
287
|
# a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
|
288
288
|
#
|
289
|
-
# ==== Polymorphic belongs_to
|
289
|
+
# ==== Polymorphic +belongs_to+
|
290
290
|
#
|
291
291
|
# Supporting polymorphic relationships is a little bit more complicated, since
|
292
292
|
# Active Record needs to know what type your association is pointing at. Something
|
@@ -311,7 +311,7 @@ module ActiveRecord
|
|
311
311
|
#
|
312
312
|
# Just provide the polymorphic target type and Active Record will take care of the rest.
|
313
313
|
#
|
314
|
-
# === has_and_belongs_to_many or has_many :through
|
314
|
+
# === +has_and_belongs_to_many+ or <tt>has_many :through</tt>
|
315
315
|
#
|
316
316
|
# Time to give our monkey some fruit.
|
317
317
|
#
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
# Returns the version of
|
4
|
+
# Returns the currently loaded version of Active Record as a <tt>Gem::Version</tt>.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
@@ -9,8 +9,8 @@ module ActiveRecord
|
|
9
9
|
module VERSION
|
10
10
|
MAJOR = 7
|
11
11
|
MINOR = 0
|
12
|
-
TINY =
|
13
|
-
PRE =
|
12
|
+
TINY = 3
|
13
|
+
PRE = nil
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
16
16
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
# Locking::Pessimistic provides support for row-level locking using
|
6
6
|
# SELECT ... FOR UPDATE and other lock types.
|
7
7
|
#
|
8
|
-
# Chain <tt>ActiveRecord::Base#find</tt> to
|
8
|
+
# Chain <tt>ActiveRecord::Base#find</tt> to ActiveRecord::QueryMethods#lock to obtain an exclusive
|
9
9
|
# lock on the selected rows:
|
10
10
|
# # select * from accounts where id=1 for update
|
11
11
|
# Account.lock.find(1)
|
@@ -81,11 +81,11 @@ module ActiveRecord
|
|
81
81
|
|
82
82
|
# Wraps the passed block in a transaction, locking the object
|
83
83
|
# before yielding. You can pass the SQL locking clause
|
84
|
-
# as an optional argument (see
|
84
|
+
# as an optional argument (see #lock!).
|
85
85
|
#
|
86
86
|
# You can also pass options like <tt>requires_new:</tt>, <tt>isolation:</tt>,
|
87
87
|
# and <tt>joinable:</tt> to the wrapping transaction (see
|
88
|
-
#
|
88
|
+
# ActiveRecord::ConnectionAdapters::DatabaseStatements#transaction).
|
89
89
|
def with_lock(*args)
|
90
90
|
transaction_opts = args.extract_options!
|
91
91
|
lock = args.present? ? args.first : true
|
@@ -22,10 +22,8 @@ module ActiveRecord
|
|
22
22
|
def strict_loading_violation(event)
|
23
23
|
debug do
|
24
24
|
owner = event.payload[:owner]
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
color("Strict loading violation: #{owner} is marked for strict loading. The #{association} association named :#{name} cannot be lazily loaded.", RED)
|
25
|
+
reflection = event.payload[:reflection]
|
26
|
+
color(reflection.strict_loading_violation_message(owner), RED)
|
29
27
|
end
|
30
28
|
end
|
31
29
|
|
@@ -51,7 +49,14 @@ module ActiveRecord
|
|
51
49
|
|
52
50
|
binds = []
|
53
51
|
payload[:binds].each_with_index do |attr, i|
|
54
|
-
attribute_name = attr.respond_to?(:name)
|
52
|
+
attribute_name = if attr.respond_to?(:name)
|
53
|
+
attr.name
|
54
|
+
elsif attr.respond_to?(:[]) && attr[i].respond_to?(:name)
|
55
|
+
attr[i].name
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
55
60
|
filtered_params = filter(attribute_name, casted_params[i])
|
56
61
|
|
57
62
|
binds << render_bind(attr, filtered_params)
|
@@ -19,19 +19,22 @@ module ActiveRecord
|
|
19
19
|
# that informs the application when to read from a primary or read from a
|
20
20
|
# replica.
|
21
21
|
#
|
22
|
-
# To use the DatabaseSelector in your application with default settings
|
23
|
-
# the
|
22
|
+
# To use the DatabaseSelector in your application with default settings,
|
23
|
+
# run the provided generator.
|
24
24
|
#
|
25
|
-
#
|
26
|
-
# require "active_support/core_ext/integer/time"
|
25
|
+
# bin/rails g active_record:multi_db
|
27
26
|
#
|
28
|
-
#
|
27
|
+
# This will create a file named +config/initializers/multi_db.rb+ with the
|
28
|
+
# following contents:
|
29
|
+
#
|
30
|
+
# Rails.application.configure do
|
29
31
|
# config.active_record.database_selector = { delay: 2.seconds }
|
30
32
|
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
|
31
33
|
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
|
32
34
|
# end
|
33
35
|
#
|
34
|
-
#
|
36
|
+
# Alternatively you can set the options in your environment config or
|
37
|
+
# any other config file loaded on boot.
|
35
38
|
#
|
36
39
|
# The default behavior can be changed by setting the config options to a
|
37
40
|
# custom class:
|
@@ -39,6 +42,10 @@ module ActiveRecord
|
|
39
42
|
# config.active_record.database_selector = { delay: 2.seconds }
|
40
43
|
# config.active_record.database_resolver = MyResolver
|
41
44
|
# config.active_record.database_resolver_context = MyResolver::MySession
|
45
|
+
#
|
46
|
+
# Note: If you are using `rails new my_app --minimal` you will need to call
|
47
|
+
# `require "active_support/core_ext/integer/time"` to load the libaries
|
48
|
+
# for +Time+.
|
42
49
|
class DatabaseSelector
|
43
50
|
def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
|
44
51
|
@app = app
|
@@ -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
|
@@ -617,7 +617,7 @@ module ActiveRecord
|
|
617
617
|
|
618
618
|
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
|
619
619
|
else
|
620
|
-
# STI subclasses always use their superclass' table.
|
620
|
+
# STI subclasses always use their superclass's table.
|
621
621
|
base_class.table_name
|
622
622
|
end
|
623
623
|
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 }]
|
@@ -389,5 +389,19 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
389
389
|
end
|
390
390
|
end
|
391
391
|
end
|
392
|
+
|
393
|
+
initializer "active_record.unregister_current_scopes_on_unload" do |app|
|
394
|
+
config.after_initialize do
|
395
|
+
unless app.config.cache_classes
|
396
|
+
Rails.autoloaders.main.on_unload do |_cpath, value, _abspath|
|
397
|
+
# Conditions are written this way to be robust against custom
|
398
|
+
# implementations of value#is_a? or value#<.
|
399
|
+
if Class === value && ActiveRecord::Base > value
|
400
|
+
value.current_scope = nil
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
392
406
|
end
|
393
407
|
end
|
@@ -484,7 +484,7 @@ db_namespace = namespace :db do
|
|
484
484
|
namespace :load do
|
485
485
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
486
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
|
487
|
+
task name => [:load_config, :check_protected_environments] do
|
488
488
|
original_db_config = ActiveRecord::Base.connection_db_config
|
489
489
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
|
490
490
|
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config)
|
@@ -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.
|
@@ -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:
|
@@ -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
|
@@ -736,7 +736,7 @@ module ActiveRecord
|
|
736
736
|
#
|
737
737
|
# User.where(name: 'Oscar').where_values_hash
|
738
738
|
# # => {name: "Oscar"}
|
739
|
-
def where_values_hash(relation_table_name = klass.table_name)
|
739
|
+
def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
|
740
740
|
where_clause.to_h(relation_table_name)
|
741
741
|
end
|
742
742
|
|
@@ -756,7 +756,7 @@ module ActiveRecord
|
|
756
756
|
# Joins that are also marked for preloading. In which case we should just eager load them.
|
757
757
|
# Note that this is a naive implementation because we could have strings and symbols which
|
758
758
|
# 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] }
|
759
|
+
# nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
|
760
760
|
def joined_includes_values
|
761
761
|
includes_values & joins_values
|
762
762
|
end
|
@@ -917,7 +917,7 @@ module ActiveRecord
|
|
917
917
|
preload_associations(records) unless skip_preloading_value
|
918
918
|
|
919
919
|
records.each(&:readonly!) if readonly_value
|
920
|
-
records.each
|
920
|
+
records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
|
921
921
|
|
922
922
|
records
|
923
923
|
end
|