activerecord 6.0.3.3 → 6.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 +138 -0
- data/README.rdoc +1 -1
- data/lib/active_record/associations/association.rb +2 -3
- data/lib/active_record/associations/association_scope.rb +7 -1
- data/lib/active_record/associations/collection_association.rb +7 -0
- data/lib/active_record/associations/collection_proxy.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +14 -6
- data/lib/active_record/associations/join_dependency/join_association.rb +7 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +41 -23
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/autosave_association.rb +10 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +6 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +9 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -1
- data/lib/active_record/core.rb +5 -6
- data/lib/active_record/enum.rb +13 -6
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +9 -0
- data/lib/active_record/model_schema.rb +29 -0
- data/lib/active_record/reflection.rb +11 -13
- data/lib/active_record/relation.rb +6 -3
- data/lib/active_record/relation/calculations.rb +1 -1
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +1 -1
- data/lib/active_record/relation/merger.rb +7 -2
- data/lib/active_record/relation/query_methods.rb +23 -11
- data/lib/active_record/scoping/named.rb +5 -0
- data/lib/active_record/test_fixtures.rb +19 -1
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/validations/associated.rb +1 -1
- 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: 1fc6a79e2176d3edc373f3f920c287f8f1bd35123e3af17f52034282f4f15735
|
4
|
+
data.tar.gz: 91b8b7c4107316e3b09b3176acf6b7fea744976df609f292b192033923962a4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad92ac3aaab6f497944161e777415d90cb0c1e61d8d297d571d18cb017d430a8bbf0dc97289cec4f19620e0421641c42917c4bbeaba9fe4638c0601d1c0c50ed
|
7
|
+
data.tar.gz: b8094270448f085b549609e682be83489ab08a0d56f6b7946d6f525b4c20f32bf8847dc89a0696ae7e63231213cddbac16a78cc17a43f1c2591063f34a07644d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,141 @@
|
|
1
|
+
## Rails 6.0.4 (June 15, 2021) ##
|
2
|
+
|
3
|
+
* Only warn about negative enums if a positive form that would cause conflicts exists.
|
4
|
+
|
5
|
+
Fixes #39065.
|
6
|
+
|
7
|
+
*Alex Ghiculescu*
|
8
|
+
|
9
|
+
* Allow the inverse of a `has_one` association that was previously autosaved to be loaded.
|
10
|
+
|
11
|
+
Fixes #34255.
|
12
|
+
|
13
|
+
*Steven Weber*
|
14
|
+
|
15
|
+
* Reset statement cache for association if `table_name` is changed.
|
16
|
+
|
17
|
+
Fixes #36453.
|
18
|
+
|
19
|
+
*Ryuta Kamizono*
|
20
|
+
|
21
|
+
* Type cast extra select for eager loading.
|
22
|
+
|
23
|
+
*Ryuta Kamizono*
|
24
|
+
|
25
|
+
* Prevent collection associations from being autosaved multiple times.
|
26
|
+
|
27
|
+
Fixes #39173.
|
28
|
+
|
29
|
+
*Eugene Kenny*
|
30
|
+
|
31
|
+
* Resolve issue with insert_all unique_by option when used with expression index.
|
32
|
+
|
33
|
+
When the `:unique_by` option of `ActiveRecord::Persistence.insert_all` and
|
34
|
+
`ActiveRecord::Persistence.upsert_all` was used with the name of an expression index, an error
|
35
|
+
was raised. Adding a guard around the formatting behavior for the `:unique_by` corrects this.
|
36
|
+
|
37
|
+
Usage:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
create_table :books, id: :integer, force: true do |t|
|
41
|
+
t.column :name, :string
|
42
|
+
t.index "lower(name)", unique: true
|
43
|
+
end
|
44
|
+
|
45
|
+
Book.insert_all [{ name: "MyTest" }], unique_by: :index_books_on_lower_name
|
46
|
+
```
|
47
|
+
|
48
|
+
Fixes #39516.
|
49
|
+
|
50
|
+
*Austen Madden*
|
51
|
+
|
52
|
+
* Fix preloading for polymorphic association with custom scope.
|
53
|
+
|
54
|
+
*Ryuta Kamizono*
|
55
|
+
|
56
|
+
* Allow relations with different SQL comments in the `or` method.
|
57
|
+
|
58
|
+
*Takumi Shotoku*
|
59
|
+
|
60
|
+
* Resolve conflict between counter cache and optimistic locking.
|
61
|
+
|
62
|
+
Bump an Active Record instance's lock version after updating its counter
|
63
|
+
cache. This avoids raising an unnecessary `ActiveRecord::StaleObjectError`
|
64
|
+
upon subsequent transactions by maintaining parity with the corresponding
|
65
|
+
database record's `lock_version` column.
|
66
|
+
|
67
|
+
Fixes #16449.
|
68
|
+
|
69
|
+
*Aaron Lipman*
|
70
|
+
|
71
|
+
* Fix through association with source/through scope which has joins.
|
72
|
+
|
73
|
+
*Ryuta Kamizono*
|
74
|
+
|
75
|
+
* Fix through association to respect source scope for includes/preload.
|
76
|
+
|
77
|
+
*Ryuta Kamizono*
|
78
|
+
|
79
|
+
* Fix eager load with Arel joins to maintain the original joins order.
|
80
|
+
|
81
|
+
*Ryuta Kamizono*
|
82
|
+
|
83
|
+
* Fix group by count with eager loading + order + limit/offset.
|
84
|
+
|
85
|
+
*Ryuta Kamizono*
|
86
|
+
|
87
|
+
* Fix left joins order when merging multiple left joins from different associations.
|
88
|
+
|
89
|
+
*Ryuta Kamizono*
|
90
|
+
|
91
|
+
* Fix index creation to preserve index comment in bulk change table on MySQL.
|
92
|
+
|
93
|
+
*Ryuta Kamizono*
|
94
|
+
|
95
|
+
* Change `remove_foreign_key` to not check `:validate` option if database
|
96
|
+
doesn't support the feature.
|
97
|
+
|
98
|
+
*Ryuta Kamizono*
|
99
|
+
|
100
|
+
* Fix the result of aggregations to maintain duplicated "group by" fields.
|
101
|
+
|
102
|
+
*Ryuta Kamizono*
|
103
|
+
|
104
|
+
* Do not return duplicated records when using preload.
|
105
|
+
|
106
|
+
*Bogdan Gusiev*
|
107
|
+
|
108
|
+
|
109
|
+
## Rails 6.0.3.7 (May 05, 2021) ##
|
110
|
+
|
111
|
+
* No changes.
|
112
|
+
|
113
|
+
|
114
|
+
## Rails 6.0.3.6 (March 26, 2021) ##
|
115
|
+
|
116
|
+
* No changes.
|
117
|
+
|
118
|
+
|
119
|
+
## Rails 6.0.3.5 (February 10, 2021) ##
|
120
|
+
|
121
|
+
* Fix possible DoS vector in PostgreSQL money type
|
122
|
+
|
123
|
+
Carefully crafted input can cause a DoS via the regular expressions used
|
124
|
+
for validating the money format in the PostgreSQL adapter. This patch
|
125
|
+
fixes the regexp.
|
126
|
+
|
127
|
+
Thanks to @dee-see from Hackerone for this patch!
|
128
|
+
|
129
|
+
[CVE-2021-22880]
|
130
|
+
|
131
|
+
*Aaron Patterson*
|
132
|
+
|
133
|
+
|
134
|
+
## Rails 6.0.3.4 (October 07, 2020) ##
|
135
|
+
|
136
|
+
* No changes.
|
137
|
+
|
138
|
+
|
1
139
|
## Rails 6.0.3.3 (September 09, 2020) ##
|
2
140
|
|
3
141
|
* No changes.
|
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
|
@@ -204,14 +204,13 @@ module ActiveRecord
|
|
204
204
|
scope = self.scope
|
205
205
|
return scope.to_a if skip_statement_cache?(scope)
|
206
206
|
|
207
|
-
|
208
|
-
sc = reflection.association_scope_cache(conn, owner) do |params|
|
207
|
+
sc = reflection.association_scope_cache(klass, owner) do |params|
|
209
208
|
as = AssociationScope.create { params.bind }
|
210
209
|
target_scope.merge!(as.scope(self))
|
211
210
|
end
|
212
211
|
|
213
212
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
214
|
-
sc.execute(binds,
|
213
|
+
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) } || []
|
215
214
|
end
|
216
215
|
|
217
216
|
# The scope for this association.
|
@@ -52,7 +52,7 @@ module ActiveRecord
|
|
52
52
|
attr_reader :value_transformation
|
53
53
|
|
54
54
|
def join(table, constraint)
|
55
|
-
table.create_join(table, table.create_on(constraint))
|
55
|
+
table.create_join(table, table.create_on(constraint), Arel::Nodes::LeadingJoin)
|
56
56
|
end
|
57
57
|
|
58
58
|
def last_chain_scope(scope, reflection, owner)
|
@@ -134,6 +134,12 @@ module ActiveRecord
|
|
134
134
|
|
135
135
|
if scope_chain_item == chain_head.scope
|
136
136
|
scope.merge! item.except(:where, :includes, :unscope, :order)
|
137
|
+
elsif !item.references_values.empty?
|
138
|
+
join_dependency = item.construct_join_dependency(
|
139
|
+
item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
|
140
|
+
)
|
141
|
+
scope.joins!(*item.joins_values, join_dependency)
|
142
|
+
scope.left_outer_joins!(*item.left_outer_joins_values)
|
137
143
|
end
|
138
144
|
|
139
145
|
reflection.all_includes do
|
@@ -332,6 +332,13 @@ module ActiveRecord
|
|
332
332
|
persisted + memory
|
333
333
|
end
|
334
334
|
|
335
|
+
def build_record(attributes)
|
336
|
+
previous = klass.current_scope(true) if block_given?
|
337
|
+
super
|
338
|
+
ensure
|
339
|
+
klass.current_scope = previous if previous
|
340
|
+
end
|
341
|
+
|
335
342
|
def _create_record(attributes, raise = false, &block)
|
336
343
|
unless owner.persisted?
|
337
344
|
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
@@ -106,8 +106,16 @@ module ActiveRecord
|
|
106
106
|
model_cache = Hash.new { |h, klass| h[klass] = {} }
|
107
107
|
parents = model_cache[join_root]
|
108
108
|
|
109
|
-
column_aliases = aliases.column_aliases
|
110
|
-
|
109
|
+
column_aliases = aliases.column_aliases(join_root)
|
110
|
+
column_names = explicit_selections(column_aliases, result_set)
|
111
|
+
|
112
|
+
if column_names.empty?
|
113
|
+
column_types = {}
|
114
|
+
else
|
115
|
+
column_types = result_set.column_types
|
116
|
+
column_types = column_types.slice(*column_names) unless column_types.empty?
|
117
|
+
column_aliases += column_names.map! { |name| Aliases::Column.new(name, name) }
|
118
|
+
end
|
111
119
|
|
112
120
|
message_bus = ActiveSupport::Notifications.instrumenter
|
113
121
|
|
@@ -119,7 +127,7 @@ module ActiveRecord
|
|
119
127
|
message_bus.instrument("instantiation.active_record", payload) do
|
120
128
|
result_set.each { |row_hash|
|
121
129
|
parent_key = primary_key ? row_hash[primary_key] : row_hash
|
122
|
-
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
|
130
|
+
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, column_types, &block)
|
123
131
|
construct(parent, join_root, row_hash, seen, model_cache)
|
124
132
|
}
|
125
133
|
end
|
@@ -139,9 +147,9 @@ module ActiveRecord
|
|
139
147
|
|
140
148
|
def explicit_selections(root_column_aliases, result_set)
|
141
149
|
root_names = root_column_aliases.map(&:name).to_set
|
142
|
-
result_set.columns
|
143
|
-
|
144
|
-
|
150
|
+
result_set.columns.each_with_object([]) do |name, result|
|
151
|
+
result << name unless /\At\d+_r\d+\z/.match?(name) || root_names.include?(name)
|
152
|
+
end
|
145
153
|
end
|
146
154
|
|
147
155
|
def aliases
|
@@ -33,6 +33,13 @@ module ActiveRecord
|
|
33
33
|
|
34
34
|
join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
35
35
|
|
36
|
+
unless join_scope.references_values.empty?
|
37
|
+
join_dependency = join_scope.construct_join_dependency(
|
38
|
+
join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
|
39
|
+
)
|
40
|
+
join_scope.joins!(join_dependency)
|
41
|
+
end
|
42
|
+
|
36
43
|
arel = join_scope.arel(alias_tracker.aliases)
|
37
44
|
nodes = arel.constraints.first
|
38
45
|
|
@@ -62,8 +62,8 @@ module ActiveRecord
|
|
62
62
|
hash
|
63
63
|
end
|
64
64
|
|
65
|
-
def instantiate(row, aliases, &block)
|
66
|
-
base_klass.instantiate(extract_record(row, aliases), &block)
|
65
|
+
def instantiate(row, aliases, column_types = {}, &block)
|
66
|
+
base_klass.instantiate(extract_record(row, aliases), column_types, &block)
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -94,6 +94,10 @@ module ActiveRecord
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
+
def initialize(associate_by_default: true)
|
98
|
+
@associate_by_default = associate_by_default
|
99
|
+
end
|
100
|
+
|
97
101
|
private
|
98
102
|
# Loads all the given data into +records+ for the +association+.
|
99
103
|
def preloaders_on(association, records, scope, polymorphic_parent = false)
|
@@ -142,7 +146,7 @@ module ActiveRecord
|
|
142
146
|
|
143
147
|
def preloaders_for_reflection(reflection, records, scope)
|
144
148
|
records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
|
145
|
-
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
|
149
|
+
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope, @associate_by_default).run
|
146
150
|
end
|
147
151
|
end
|
148
152
|
|
@@ -157,7 +161,7 @@ module ActiveRecord
|
|
157
161
|
end
|
158
162
|
|
159
163
|
class AlreadyLoaded # :nodoc:
|
160
|
-
def initialize(klass, owners, reflection, preload_scope)
|
164
|
+
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
|
161
165
|
@owners = owners
|
162
166
|
@reflection = reflection
|
163
167
|
end
|
@@ -4,46 +4,62 @@ module ActiveRecord
|
|
4
4
|
module Associations
|
5
5
|
class Preloader
|
6
6
|
class Association #:nodoc:
|
7
|
-
def initialize(klass, owners, reflection, preload_scope)
|
7
|
+
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
|
8
8
|
@klass = klass
|
9
|
-
@owners = owners
|
9
|
+
@owners = owners.uniq(&:__id__)
|
10
10
|
@reflection = reflection
|
11
11
|
@preload_scope = preload_scope
|
12
|
+
@associate = associate_by_default || !preload_scope || preload_scope.empty_scope?
|
12
13
|
@model = owners.first && owners.first.class
|
13
14
|
end
|
14
15
|
|
15
16
|
def run
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# the association can not be marked as loaded
|
23
|
-
# Loading into a Hash instead
|
24
|
-
records_by_owner
|
25
|
-
end
|
17
|
+
records = records_by_owner
|
18
|
+
|
19
|
+
owners.each do |owner|
|
20
|
+
associate_records_to_owner(owner, records[owner] || [])
|
21
|
+
end if @associate
|
22
|
+
|
26
23
|
self
|
27
24
|
end
|
28
25
|
|
29
26
|
def records_by_owner
|
30
|
-
|
31
|
-
|
32
|
-
@records_by_owner
|
33
|
-
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
34
|
-
(result[owner] ||= []) << record
|
35
|
-
end
|
36
|
-
end
|
27
|
+
load_records unless defined?(@records_by_owner)
|
28
|
+
|
29
|
+
@records_by_owner
|
37
30
|
end
|
38
31
|
|
39
32
|
def preloaded_records
|
40
|
-
|
41
|
-
|
33
|
+
load_records unless defined?(@preloaded_records)
|
34
|
+
|
35
|
+
@preloaded_records
|
42
36
|
end
|
43
37
|
|
44
38
|
private
|
45
39
|
attr_reader :owners, :reflection, :preload_scope, :model, :klass
|
46
40
|
|
41
|
+
def load_records
|
42
|
+
# owners can be duplicated when a relation has a collection association join
|
43
|
+
# #compare_by_identity makes such owners different hash keys
|
44
|
+
@records_by_owner = {}.compare_by_identity
|
45
|
+
raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
|
46
|
+
|
47
|
+
@preloaded_records = raw_records.select do |record|
|
48
|
+
assignments = []
|
49
|
+
|
50
|
+
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
51
|
+
entries = (@records_by_owner[owner] ||= [])
|
52
|
+
|
53
|
+
if reflection.collection? || entries.empty?
|
54
|
+
entries << record
|
55
|
+
assignments << record
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
!assignments.empty?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
47
63
|
# The name of the key on the associated records
|
48
64
|
def association_key_name
|
49
65
|
reflection.join_primary_key(klass)
|
@@ -113,7 +129,9 @@ module ActiveRecord
|
|
113
129
|
end
|
114
130
|
|
115
131
|
def reflection_scope
|
116
|
-
@reflection_scope ||=
|
132
|
+
@reflection_scope ||= begin
|
133
|
+
reflection.join_scopes(klass.arel_table, klass.predicate_builder, klass).inject(&:merge!) || klass.unscoped
|
134
|
+
end
|
117
135
|
end
|
118
136
|
|
119
137
|
def build_scope
|
@@ -123,7 +141,7 @@ module ActiveRecord
|
|
123
141
|
scope.where!(reflection.type => model.polymorphic_name)
|
124
142
|
end
|
125
143
|
|
126
|
-
scope.merge!(reflection_scope)
|
144
|
+
scope.merge!(reflection_scope) unless reflection_scope.empty_scope?
|
127
145
|
scope.merge!(preload_scope) if preload_scope
|
128
146
|
scope
|
129
147
|
end
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
module Associations
|
5
5
|
class Preloader
|
6
6
|
class ThroughAssociation < Association # :nodoc:
|
7
|
-
PRELOADER = ActiveRecord::Associations::Preloader.new
|
7
|
+
PRELOADER = ActiveRecord::Associations::Preloader.new(associate_by_default: false)
|
8
8
|
|
9
9
|
def initialize(*)
|
10
10
|
super
|
@@ -32,7 +32,7 @@ module ActiveRecord
|
|
32
32
|
reflection.chain.drop(1).each do |reflection|
|
33
33
|
relation = reflection.klass.scope_for_association
|
34
34
|
scope.merge!(
|
35
|
-
relation.except(:select, :create_with, :includes, :preload, :joins, :
|
35
|
+
relation.except(:select, :create_with, :includes, :preload, :eager_load, :joins, :left_outer_joins)
|
36
36
|
)
|
37
37
|
end
|
38
38
|
scope
|