activerecord 6.1.1 → 6.1.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +10 -0
- data/lib/active_record/associations/association.rb +7 -7
- data/lib/active_record/associations/builder/association.rb +23 -2
- data/lib/active_record/associations/join_dependency.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -6
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -1
- data/lib/active_record/connection_adapters/pool_config.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_handling.rb +11 -3
- data/lib/active_record/core.rb +42 -24
- data/lib/active_record/database_configurations/url_config.rb +1 -1
- data/lib/active_record/enum.rb +19 -13
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +14 -4
- data/lib/active_record/log_subscriber.rb +3 -2
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/reflection.rb +1 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +2 -0
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4112bd4b4d7a00b26db10332f2f6452d2b6ad1fdf3f2ad50988a8229abac9192
|
4
|
+
data.tar.gz: 6fbcb021ae1942e307730ef7aaad54d1f594cd52b749d407f8aafe052bee6794
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb1830fe0587253ecede381d53dd0be5c8de80070559458653d4a6e149c002a03a3ba37a8723e0e869693500b55ec9956f9f18d2d556884f40d28ac9af0e34f6
|
7
|
+
data.tar.gz: d78aeab68b5c4d4d0e2d8a315b7175a0257b6e1bb6db82c1ae04551f44540d72ffd122881af9cfb93cf8c0d8d57b6310a5bd303e612e24795f54fc07b777f307
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,53 @@
|
|
1
|
+
## Rails 6.1.2 (February 09, 2021) ##
|
2
|
+
|
3
|
+
* Fix timestamp type for sqlite3.
|
4
|
+
|
5
|
+
*Eileen M. Uchitelle*
|
6
|
+
|
7
|
+
* Make destroy async transactional.
|
8
|
+
|
9
|
+
An active record rollback could occur while enqueuing a job. In this
|
10
|
+
case the job would enqueue even though the database deletion
|
11
|
+
rolledback putting things in a funky state.
|
12
|
+
|
13
|
+
Now the jobs are only enqueued until after the db transaction has been committed.
|
14
|
+
|
15
|
+
*Cory Gwin*
|
16
|
+
|
17
|
+
* Fix malformed packet error in MySQL statement for connection configuration.
|
18
|
+
|
19
|
+
*robinroestenburg*
|
20
|
+
|
21
|
+
* Connection specification now passes the "url" key as a configuration for the
|
22
|
+
adapter if the "url" protocol is "jdbc", "http", or "https". Previously only
|
23
|
+
urls with the "jdbc" prefix were passed to the Active Record Adapter, others
|
24
|
+
are assumed to be adapter specification urls.
|
25
|
+
|
26
|
+
Fixes #41137.
|
27
|
+
|
28
|
+
*Jonathan Bracy*
|
29
|
+
|
30
|
+
* Fix granular connection swapping when there are multiple abstract classes.
|
31
|
+
|
32
|
+
*Eileen M. Uchitelle*
|
33
|
+
|
34
|
+
* Fix `find_by` with custom primary key for belongs_to association.
|
35
|
+
|
36
|
+
*Ryuta Kamizono*
|
37
|
+
|
38
|
+
* Add support for `rails console --sandbox` for multiple database applications.
|
39
|
+
|
40
|
+
*alpaca-tc*
|
41
|
+
|
42
|
+
* Fix `where` on polymorphic association with empty array.
|
43
|
+
|
44
|
+
*Ryuta Kamizono*
|
45
|
+
|
46
|
+
* Fix preventing writes for `ApplicationRecord`.
|
47
|
+
|
48
|
+
*Eileen M. Uchitelle*
|
49
|
+
|
50
|
+
|
1
51
|
## Rails 6.1.1 (January 07, 2021) ##
|
2
52
|
|
3
53
|
* Fix fixtures loading when strict loading is enabled for the association.
|
data/README.rdoc
CHANGED
@@ -194,7 +194,7 @@ The latest version of Active Record can be installed with RubyGems:
|
|
194
194
|
|
195
195
|
Source code can be downloaded as part of the Rails project on GitHub:
|
196
196
|
|
197
|
-
* https://github.com/rails/rails/tree/
|
197
|
+
* https://github.com/rails/rails/tree/main/activerecord
|
198
198
|
|
199
199
|
|
200
200
|
== License
|
@@ -27,6 +27,16 @@ module ActiveRecord
|
|
27
27
|
RUBY
|
28
28
|
end
|
29
29
|
|
30
|
+
def build(attributes = nil, &block)
|
31
|
+
if attributes.is_a?(Array)
|
32
|
+
attributes.collect { |attr| build(attr, &block) }
|
33
|
+
else
|
34
|
+
block = current_scope_restoring_block(&block)
|
35
|
+
scoping { _new(attributes, &block) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
alias new build
|
39
|
+
|
30
40
|
private
|
31
41
|
def _new(attributes, &block)
|
32
42
|
@association.build(attributes, &block)
|
@@ -211,12 +211,8 @@ module ActiveRecord
|
|
211
211
|
|
212
212
|
private
|
213
213
|
def find_target
|
214
|
-
if owner.strict_loading? && owner.validation_context.nil?
|
215
|
-
Base.strict_loading_violation!(owner: owner.class,
|
216
|
-
end
|
217
|
-
|
218
|
-
if reflection.strict_loading? && owner.validation_context.nil?
|
219
|
-
Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
|
214
|
+
if (owner.strict_loading? || reflection.strict_loading?) && owner.validation_context.nil?
|
215
|
+
Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
|
220
216
|
end
|
221
217
|
|
222
218
|
scope = self.scope
|
@@ -331,7 +327,11 @@ module ActiveRecord
|
|
331
327
|
end
|
332
328
|
|
333
329
|
def enqueue_destroy_association(options)
|
334
|
-
owner.class.destroy_association_async_job
|
330
|
+
job_class = owner.class.destroy_association_async_job
|
331
|
+
|
332
|
+
if job_class
|
333
|
+
owner._after_commit_jobs.push([job_class, options])
|
334
|
+
end
|
335
335
|
end
|
336
336
|
|
337
337
|
def inversable?(record)
|
@@ -76,6 +76,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
76
76
|
if dependent = reflection.options[:dependent]
|
77
77
|
check_dependent_options(dependent, model)
|
78
78
|
add_destroy_callbacks(model, reflection)
|
79
|
+
add_after_commit_jobs_callback(model, dependent)
|
79
80
|
end
|
80
81
|
|
81
82
|
Association.extensions.each do |extension|
|
@@ -132,11 +133,31 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
132
133
|
|
133
134
|
def self.add_destroy_callbacks(model, reflection)
|
134
135
|
name = reflection.name
|
135
|
-
model.before_destroy
|
136
|
+
model.before_destroy(->(o) { o.association(name).handle_dependency })
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.add_after_commit_jobs_callback(model, dependent)
|
140
|
+
if dependent == :destroy_async
|
141
|
+
mixin = model.generated_association_methods
|
142
|
+
|
143
|
+
unless mixin.method_defined?(:_after_commit_jobs)
|
144
|
+
model.after_commit(-> do
|
145
|
+
_after_commit_jobs.each do |job_class, job_arguments|
|
146
|
+
job_class.perform_later(**job_arguments)
|
147
|
+
end
|
148
|
+
end)
|
149
|
+
|
150
|
+
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
151
|
+
def _after_commit_jobs
|
152
|
+
@_after_commit_jobs ||= []
|
153
|
+
end
|
154
|
+
CODE
|
155
|
+
end
|
156
|
+
end
|
136
157
|
end
|
137
158
|
|
138
159
|
private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
|
139
160
|
:define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
|
140
|
-
:valid_dependent_options, :check_dependent_options, :add_destroy_callbacks
|
161
|
+
:valid_dependent_options, :check_dependent_options, :add_destroy_callbacks, :add_after_commit_jobs_callback
|
141
162
|
end
|
142
163
|
end
|
@@ -195,7 +195,7 @@ module ActiveRecord
|
|
195
195
|
next table, true
|
196
196
|
end
|
197
197
|
|
198
|
-
table_name = @references[reflection.name.to_sym]
|
198
|
+
table_name = @references[reflection.name.to_sym]&.to_s
|
199
199
|
|
200
200
|
table = alias_tracker.aliased_table_for(reflection.klass.arel_table, table_name) do
|
201
201
|
name = reflection.alias_candidate(parent.table_name)
|
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
|
25
25
|
attr_accessor :schema_cache
|
26
26
|
|
27
|
-
def
|
27
|
+
def connection_klass
|
28
28
|
nil
|
29
29
|
end
|
30
30
|
end
|
@@ -360,7 +360,7 @@ module ActiveRecord
|
|
360
360
|
include ConnectionAdapters::AbstractPool
|
361
361
|
|
362
362
|
attr_accessor :automatic_reconnect, :checkout_timeout
|
363
|
-
attr_reader :db_config, :size, :reaper, :pool_config, :
|
363
|
+
attr_reader :db_config, :size, :reaper, :pool_config, :connection_klass
|
364
364
|
|
365
365
|
delegate :schema_cache, :schema_cache=, to: :pool_config
|
366
366
|
|
@@ -375,7 +375,7 @@ module ActiveRecord
|
|
375
375
|
|
376
376
|
@pool_config = pool_config
|
377
377
|
@db_config = pool_config.db_config
|
378
|
-
@
|
378
|
+
@connection_klass = pool_config.connection_klass
|
379
379
|
|
380
380
|
@checkout_timeout = db_config.checkout_timeout
|
381
381
|
@idle_timeout = db_config.idle_timeout
|
@@ -1040,7 +1040,7 @@ module ActiveRecord
|
|
1040
1040
|
end
|
1041
1041
|
alias :connection_pools :connection_pool_list
|
1042
1042
|
|
1043
|
-
def establish_connection(config, owner_name: Base
|
1043
|
+
def establish_connection(config, owner_name: Base, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
|
1044
1044
|
owner_name = config.to_s if config.is_a?(Symbol)
|
1045
1045
|
|
1046
1046
|
pool_config = resolve_pool_config(config, owner_name)
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
module QueryCache
|
8
8
|
class << self
|
9
9
|
def included(base) #:nodoc:
|
10
|
-
dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
|
10
|
+
dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
|
11
11
|
:rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
|
12
12
|
|
13
13
|
base.set_callback :checkout, :after, :configure_query_cache!
|
@@ -111,7 +111,7 @@ module ActiveRecord
|
|
111
111
|
@config.fetch(:use_metadata_table, true)
|
112
112
|
end
|
113
113
|
|
114
|
-
# Determines whether writes are currently being
|
114
|
+
# Determines whether writes are currently being prevented.
|
115
115
|
#
|
116
116
|
# Returns true if the connection is a replica.
|
117
117
|
#
|
@@ -123,10 +123,9 @@ module ActiveRecord
|
|
123
123
|
def preventing_writes?
|
124
124
|
return true if replica?
|
125
125
|
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
|
126
|
-
return false if
|
126
|
+
return false if connection_klass.nil?
|
127
127
|
|
128
|
-
|
129
|
-
klass&.current_preventing_writes
|
128
|
+
connection_klass.current_preventing_writes
|
130
129
|
end
|
131
130
|
|
132
131
|
def migrations_paths # :nodoc:
|
@@ -202,8 +201,8 @@ module ActiveRecord
|
|
202
201
|
@owner = Thread.current
|
203
202
|
end
|
204
203
|
|
205
|
-
def
|
206
|
-
@pool.
|
204
|
+
def connection_klass # :nodoc:
|
205
|
+
@pool.connection_klass
|
207
206
|
end
|
208
207
|
|
209
208
|
def schema_cache
|
@@ -751,6 +751,11 @@ module ActiveRecord
|
|
751
751
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
752
752
|
variables["wait_timeout"] = wait_timeout
|
753
753
|
|
754
|
+
# Set the collation of the connection character set.
|
755
|
+
if @config[:collation]
|
756
|
+
variables["collation_connection"] = @config[:collation]
|
757
|
+
end
|
758
|
+
|
754
759
|
defaults = [":default", :default].to_set
|
755
760
|
|
756
761
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
@@ -770,15 +775,6 @@ module ActiveRecord
|
|
770
775
|
end
|
771
776
|
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
772
777
|
|
773
|
-
# NAMES does not have an equals sign, see
|
774
|
-
# https://dev.mysql.com/doc/refman/en/set-names.html
|
775
|
-
# (trailing comma because variable_assignments will always have content)
|
776
|
-
if @config[:encoding]
|
777
|
-
encoding = +"NAMES #{@config[:encoding]}"
|
778
|
-
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
779
|
-
encoding << ", "
|
780
|
-
end
|
781
|
-
|
782
778
|
# Gather up all of the SET variables...
|
783
779
|
variable_assignments = variables.map do |k, v|
|
784
780
|
if defaults.include?(v)
|
@@ -790,7 +786,7 @@ module ActiveRecord
|
|
790
786
|
end.compact.join(", ")
|
791
787
|
|
792
788
|
# ...and send them all in one query
|
793
|
-
execute("SET #{
|
789
|
+
execute("SET #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
794
790
|
end
|
795
791
|
|
796
792
|
def column_definitions(table_name) # :nodoc:
|
@@ -79,7 +79,10 @@ module ActiveRecord
|
|
79
79
|
" WHERE table_schema = #{scope[:schema]}" \
|
80
80
|
" AND table_name = #{scope[:name]}" \
|
81
81
|
" AND column_name = #{column_name}"
|
82
|
-
|
82
|
+
# Calling .inspect leads into issues with the query result
|
83
|
+
# which already returns escaped quotes.
|
84
|
+
# We remove the escape sequence from the result in order to deal with double escaping issues.
|
85
|
+
@connection.query_value(sql, "SCHEMA").gsub("\\'", "'").inspect
|
83
86
|
end
|
84
87
|
end
|
85
88
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
class PoolConfig # :nodoc:
|
6
6
|
include Mutex_m
|
7
7
|
|
8
|
-
attr_reader :db_config, :
|
8
|
+
attr_reader :db_config, :connection_klass
|
9
9
|
attr_accessor :schema_cache
|
10
10
|
|
11
11
|
INSTANCES = ObjectSpace::WeakMap.new
|
@@ -17,14 +17,24 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(connection_klass, db_config)
|
21
21
|
super()
|
22
|
-
@
|
22
|
+
@connection_klass = connection_klass
|
23
23
|
@db_config = db_config
|
24
24
|
@pool = nil
|
25
25
|
INSTANCES[self] = self
|
26
26
|
end
|
27
27
|
|
28
|
+
def connection_specification_name
|
29
|
+
if connection_klass.is_a?(String)
|
30
|
+
connection_klass
|
31
|
+
elsif connection_klass.primary_class?
|
32
|
+
"ActiveRecord::Base"
|
33
|
+
else
|
34
|
+
connection_klass.name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def disconnect!
|
29
39
|
ActiveSupport::ForkTracker.check!
|
30
40
|
|
@@ -649,9 +649,7 @@ module ActiveRecord
|
|
649
649
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
650
650
|
end
|
651
651
|
|
652
|
-
if without_prepared_statement?(binds)
|
653
|
-
result = exec_no_cache(sql, name, [])
|
654
|
-
elsif !prepare
|
652
|
+
if !prepare || without_prepared_statement?(binds)
|
655
653
|
result = exec_no_cache(sql, name, binds)
|
656
654
|
else
|
657
655
|
result = exec_cache(sql, name, binds)
|
@@ -271,7 +271,7 @@ module ActiveRecord
|
|
271
271
|
def change_column(table_name, column_name, type, **options) #:nodoc:
|
272
272
|
alter_table(table_name) do |definition|
|
273
273
|
definition[column_name].instance_eval do
|
274
|
-
self.type = type
|
274
|
+
self.type = aliased_types(type.to_s, type)
|
275
275
|
self.options.merge!(options)
|
276
276
|
end
|
277
277
|
end
|
@@ -91,6 +91,7 @@ module ActiveRecord
|
|
91
91
|
db_config, owner_name = resolve_config_for_connection(database_key)
|
92
92
|
handler = lookup_connection_handler(role.to_sym)
|
93
93
|
|
94
|
+
self.connection_class = true
|
94
95
|
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
95
96
|
end
|
96
97
|
|
@@ -99,6 +100,7 @@ module ActiveRecord
|
|
99
100
|
db_config, owner_name = resolve_config_for_connection(database_key)
|
100
101
|
handler = lookup_connection_handler(role.to_sym)
|
101
102
|
|
103
|
+
self.connection_class = true
|
102
104
|
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role, shard: shard.to_sym)
|
103
105
|
end
|
104
106
|
end
|
@@ -143,6 +145,10 @@ module ActiveRecord
|
|
143
145
|
if self != Base && !abstract_class
|
144
146
|
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
145
147
|
end
|
148
|
+
|
149
|
+
if name != connection_specification_name && !primary_class?
|
150
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
|
151
|
+
end
|
146
152
|
end
|
147
153
|
|
148
154
|
if database && (role || shard)
|
@@ -180,12 +186,14 @@ module ActiveRecord
|
|
180
186
|
#
|
181
187
|
# Usage:
|
182
188
|
#
|
183
|
-
# ActiveRecord::Base.
|
189
|
+
# ActiveRecord::Base.connected_to_many(AnimalsRecord, MealsRecord, role: :reading) do
|
184
190
|
# Dog.first # Read from animals replica
|
185
191
|
# Dinner.first # Read from meals replica
|
186
192
|
# Person.first # Read from primary writer
|
187
193
|
# end
|
188
|
-
def connected_to_many(classes, role:, shard: nil, prevent_writes: false)
|
194
|
+
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
|
195
|
+
classes = classes.flatten
|
196
|
+
|
189
197
|
if legacy_connection_handling
|
190
198
|
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
191
199
|
end
|
@@ -357,7 +365,7 @@ module ActiveRecord
|
|
357
365
|
self.connection_specification_name = owner_name
|
358
366
|
|
359
367
|
db_config = Base.configurations.resolve(config_or_env)
|
360
|
-
[db_config,
|
368
|
+
[db_config, self]
|
361
369
|
end
|
362
370
|
|
363
371
|
def with_handler(handler_key, &blk)
|
data/lib/active_record/core.rb
CHANGED
@@ -196,7 +196,7 @@ module ActiveRecord
|
|
196
196
|
else
|
197
197
|
connected_to_stack.reverse_each do |hash|
|
198
198
|
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
199
|
-
return hash[:role] if hash[:role] && hash[:klasses].include?(
|
199
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_classes)
|
200
200
|
end
|
201
201
|
|
202
202
|
default_role
|
@@ -215,7 +215,7 @@ module ActiveRecord
|
|
215
215
|
def self.current_shard
|
216
216
|
connected_to_stack.reverse_each do |hash|
|
217
217
|
return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
|
218
|
-
return hash[:shard] if hash[:shard] && hash[:klasses].include?(
|
218
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_classes)
|
219
219
|
end
|
220
220
|
|
221
221
|
default_shard
|
@@ -237,7 +237,7 @@ module ActiveRecord
|
|
237
237
|
else
|
238
238
|
connected_to_stack.reverse_each do |hash|
|
239
239
|
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
240
|
-
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(
|
240
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_classes)
|
241
241
|
end
|
242
242
|
|
243
243
|
false
|
@@ -254,11 +254,23 @@ module ActiveRecord
|
|
254
254
|
end
|
255
255
|
end
|
256
256
|
|
257
|
-
def self.
|
257
|
+
def self.connection_class=(b) # :nodoc:
|
258
|
+
@connection_class = b
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.connection_class # :nodoc
|
262
|
+
@connection_class ||= false
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.connection_class? # :nodoc:
|
266
|
+
self.connection_class
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.connection_classes # :nodoc:
|
258
270
|
klass = self
|
259
271
|
|
260
272
|
until klass == Base
|
261
|
-
break if klass.
|
273
|
+
break if klass.connection_class?
|
262
274
|
klass = klass.superclass
|
263
275
|
end
|
264
276
|
|
@@ -277,14 +289,14 @@ module ActiveRecord
|
|
277
289
|
self.default_role = writing_role
|
278
290
|
self.default_shard = :default
|
279
291
|
|
280
|
-
def self.strict_loading_violation!(owner:,
|
292
|
+
def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
|
281
293
|
case action_on_strict_loading_violation
|
282
294
|
when :raise
|
283
|
-
message = "`#{
|
295
|
+
message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
|
284
296
|
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
285
297
|
when :log
|
286
298
|
name = "strict_loading_violation.active_record"
|
287
|
-
ActiveSupport::Notifications.instrument(name, owner: owner,
|
299
|
+
ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
|
288
300
|
end
|
289
301
|
end
|
290
302
|
end
|
@@ -332,31 +344,37 @@ module ActiveRecord
|
|
332
344
|
hash = args.first
|
333
345
|
return super unless Hash === hash
|
334
346
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
347
|
+
hash = hash.each_with_object({}) do |(key, value), h|
|
348
|
+
key = key.to_s
|
349
|
+
key = attribute_aliases[key] || key
|
350
|
+
|
351
|
+
return super if reflect_on_aggregation(key)
|
352
|
+
|
353
|
+
reflection = _reflect_on_association(key)
|
354
|
+
|
355
|
+
if !reflection
|
356
|
+
value = value.id if value.respond_to?(:id)
|
357
|
+
elsif reflection.belongs_to? && !reflection.polymorphic?
|
358
|
+
key = reflection.join_foreign_key
|
359
|
+
pkey = reflection.join_primary_key
|
360
|
+
value = value.public_send(pkey) if value.respond_to?(pkey)
|
348
361
|
end
|
349
|
-
end
|
350
362
|
|
351
|
-
|
363
|
+
if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
|
364
|
+
return super
|
365
|
+
end
|
366
|
+
|
367
|
+
h[key] = value
|
368
|
+
end
|
352
369
|
|
370
|
+
keys = hash.keys
|
353
371
|
statement = cached_find_by_statement(keys) { |params|
|
354
372
|
wheres = keys.index_with { params.bind }
|
355
373
|
where(wheres).limit(1)
|
356
374
|
}
|
357
375
|
|
358
376
|
begin
|
359
|
-
statement.execute(values, connection).first
|
377
|
+
statement.execute(hash.values, connection).first
|
360
378
|
rescue TypeError
|
361
379
|
raise ActiveRecord::StatementInvalid
|
362
380
|
end
|
@@ -42,7 +42,7 @@ module ActiveRecord
|
|
42
42
|
# Return a Hash that can be merged into the main config that represents
|
43
43
|
# the passed in url
|
44
44
|
def build_url_hash
|
45
|
-
if url.nil? || url.start_with?(
|
45
|
+
if url.nil? || %w(jdbc: http: https:).any? { |protocol| url.start_with?(protocol) }
|
46
46
|
{ url: url }
|
47
47
|
else
|
48
48
|
ConnectionUrlResolver.new(url).to_hash
|
data/lib/active_record/enum.rb
CHANGED
@@ -187,27 +187,33 @@ module ActiveRecord
|
|
187
187
|
|
188
188
|
value_method_names = []
|
189
189
|
_enum_methods_module.module_eval do
|
190
|
-
|
191
|
-
|
190
|
+
prefix = if enum_prefix == true
|
191
|
+
"#{name}_"
|
192
|
+
elsif enum_prefix
|
193
|
+
"#{enum_prefix}_"
|
194
|
+
end
|
192
195
|
|
193
|
-
|
194
|
-
|
196
|
+
suffix = if enum_suffix == true
|
197
|
+
"_#{name}"
|
198
|
+
elsif enum_suffix
|
199
|
+
"_#{enum_suffix}"
|
200
|
+
end
|
195
201
|
|
196
202
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
197
203
|
pairs.each do |label, value|
|
198
|
-
label = label.to_s
|
199
204
|
enum_values[label] = value
|
205
|
+
label = label.to_s
|
200
206
|
|
201
207
|
value_method_name = "#{prefix}#{label}#{suffix}"
|
202
208
|
value_method_names << value_method_name
|
203
|
-
define_enum_methods(name, value_method_name,
|
209
|
+
define_enum_methods(name, value_method_name, value, enum_scopes)
|
204
210
|
|
205
211
|
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
206
212
|
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
207
213
|
|
208
214
|
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
209
215
|
value_method_names << value_method_alias
|
210
|
-
define_enum_methods(name, value_method_alias,
|
216
|
+
define_enum_methods(name, value_method_alias, value, enum_scopes)
|
211
217
|
end
|
212
218
|
end
|
213
219
|
end
|
@@ -225,23 +231,23 @@ module ActiveRecord
|
|
225
231
|
private
|
226
232
|
attr_reader :klass
|
227
233
|
|
228
|
-
def define_enum_methods(name, value_method_name,
|
229
|
-
# def active?()
|
234
|
+
def define_enum_methods(name, value_method_name, value, enum_scopes)
|
235
|
+
# def active?() status_for_database == 0 end
|
230
236
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
231
|
-
define_method("#{value_method_name}?") {
|
237
|
+
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
232
238
|
|
233
239
|
# def active!() update!(status: 0) end
|
234
240
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
235
|
-
define_method("#{value_method_name}!") { update!(name =>
|
241
|
+
define_method("#{value_method_name}!") { update!(name => value) }
|
236
242
|
|
237
243
|
# scope :active, -> { where(status: 0) }
|
238
244
|
# scope :not_active, -> { where.not(status: 0) }
|
239
245
|
if enum_scopes != false
|
240
246
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
241
|
-
klass.scope value_method_name, -> { where(name =>
|
247
|
+
klass.scope value_method_name, -> { where(name => value) }
|
242
248
|
|
243
249
|
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
244
|
-
klass.scope "not_#{value_method_name}", -> { where.not(name =>
|
250
|
+
klass.scope "not_#{value_method_name}", -> { where.not(name => value) }
|
245
251
|
end
|
246
252
|
end
|
247
253
|
end
|
@@ -89,7 +89,9 @@ module ActiveRecord
|
|
89
89
|
|
90
90
|
begin
|
91
91
|
locking_column = self.class.locking_column
|
92
|
-
|
92
|
+
lock_attribute_was = @attributes[locking_column]
|
93
|
+
lock_value_for_database = _lock_value_for_database(locking_column)
|
94
|
+
|
93
95
|
attribute_names = attribute_names.dup if attribute_names.frozen?
|
94
96
|
attribute_names << locking_column
|
95
97
|
|
@@ -98,7 +100,7 @@ module ActiveRecord
|
|
98
100
|
affected_rows = self.class._update_record(
|
99
101
|
attributes_with_values(attribute_names),
|
100
102
|
@primary_key => id_in_database,
|
101
|
-
locking_column =>
|
103
|
+
locking_column => lock_value_for_database
|
102
104
|
)
|
103
105
|
|
104
106
|
if affected_rows != 1
|
@@ -109,7 +111,7 @@ module ActiveRecord
|
|
109
111
|
|
110
112
|
# If something went wrong, revert the locking_column value.
|
111
113
|
rescue Exception
|
112
|
-
|
114
|
+
@attributes[locking_column] = lock_attribute_was
|
113
115
|
raise
|
114
116
|
end
|
115
117
|
end
|
@@ -121,7 +123,7 @@ module ActiveRecord
|
|
121
123
|
|
122
124
|
affected_rows = self.class._delete_record(
|
123
125
|
@primary_key => id_in_database,
|
124
|
-
locking_column =>
|
126
|
+
locking_column => _lock_value_for_database(locking_column)
|
125
127
|
)
|
126
128
|
|
127
129
|
if affected_rows != 1
|
@@ -131,6 +133,14 @@ module ActiveRecord
|
|
131
133
|
affected_rows
|
132
134
|
end
|
133
135
|
|
136
|
+
def _lock_value_for_database(locking_column)
|
137
|
+
if will_save_change_to_attribute?(locking_column)
|
138
|
+
@attributes[locking_column].value_for_database
|
139
|
+
else
|
140
|
+
@attributes[locking_column].original_value_for_database
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
134
144
|
module ClassMethods
|
135
145
|
DEFAULT_LOCKING_COLUMN = "lock_version"
|
136
146
|
|
@@ -22,9 +22,10 @@ module ActiveRecord
|
|
22
22
|
def strict_loading_violation(event)
|
23
23
|
debug do
|
24
24
|
owner = event.payload[:owner]
|
25
|
-
association = event.payload[:
|
25
|
+
association = event.payload[:reflection].klass
|
26
|
+
name = event.payload[:reflection].name
|
26
27
|
|
27
|
-
color("Strict loading violation: #{
|
28
|
+
color("Strict loading violation: #{owner} is marked for strict loading. The #{association} association named :#{name} cannot be lazily loaded.", RED)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
ActiveRecord::
|
4
|
-
|
5
|
-
at_exit do
|
6
|
-
ActiveRecord::Base.connection.rollback_transaction
|
3
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.set_callback(:checkout, :after) do
|
4
|
+
begin_transaction(joinable: false)
|
7
5
|
end
|
@@ -162,7 +162,7 @@ module ActiveRecord
|
|
162
162
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
163
163
|
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
164
164
|
def class_name
|
165
|
-
@class_name ||= -(options[:class_name]
|
165
|
+
@class_name ||= -(options[:class_name] || derive_class_name).to_s
|
166
166
|
end
|
167
167
|
|
168
168
|
# Returns a list of scopes that should be applied for this Reflection
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.1.
|
4
|
+
version: 6.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.1.
|
19
|
+
version: 6.1.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.1.
|
26
|
+
version: 6.1.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 6.1.
|
33
|
+
version: 6.1.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 6.1.
|
40
|
+
version: 6.1.2
|
41
41
|
description: Databases on Rails. Build a persistent domain model by mapping database
|
42
42
|
tables to Ruby classes. Strong conventions for associations, validations, aggregations,
|
43
43
|
migrations, and testing come baked-in.
|
@@ -390,10 +390,10 @@ licenses:
|
|
390
390
|
- MIT
|
391
391
|
metadata:
|
392
392
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
393
|
-
changelog_uri: https://github.com/rails/rails/blob/v6.1.
|
394
|
-
documentation_uri: https://api.rubyonrails.org/v6.1.
|
393
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.1.2/activerecord/CHANGELOG.md
|
394
|
+
documentation_uri: https://api.rubyonrails.org/v6.1.2/
|
395
395
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
396
|
-
source_code_uri: https://github.com/rails/rails/tree/v6.1.
|
396
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.1.2/activerecord
|
397
397
|
post_install_message:
|
398
398
|
rdoc_options:
|
399
399
|
- "--main"
|