activerecord 6.0.3.6 → 6.0.4.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 +123 -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/join_association.rb +7 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +14 -6
- 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/preloader.rb +6 -2
- 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/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/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/relation.rb +6 -3
- 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 +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88afaa50cc998c6a17ae5d4685b6b347c05a04360ac54f8130a9a08f4933136b
|
4
|
+
data.tar.gz: bfd6b05fcaf68e62f9e99d2d0be51ce298805ab3f34151449b0fd1fa6d93e87c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ad949a111141d5dd29f74d7667002ca24797b00ab3b299be58b7360fc662d9350333b462f3a5bd65e1e63ebfc61542ba748bb9c68fb417e75e257a3f52c81f0
|
7
|
+
data.tar.gz: 2ed993c948432001d6917b7c89b182e360bdd47db27aadcdd6a979720ebe9a9c33c26a3aaa18b449720859ad6606a038f1114a089e4bcd6793f68e8cb24f288b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,126 @@
|
|
1
|
+
## Rails 6.0.4.2 (December 14, 2021) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 6.0.4.1 (August 19, 2021) ##
|
7
|
+
|
8
|
+
* No changes.
|
9
|
+
|
10
|
+
|
11
|
+
## Rails 6.0.4 (June 15, 2021) ##
|
12
|
+
|
13
|
+
* Only warn about negative enums if a positive form that would cause conflicts exists.
|
14
|
+
|
15
|
+
Fixes #39065.
|
16
|
+
|
17
|
+
*Alex Ghiculescu*
|
18
|
+
|
19
|
+
* Allow the inverse of a `has_one` association that was previously autosaved to be loaded.
|
20
|
+
|
21
|
+
Fixes #34255.
|
22
|
+
|
23
|
+
*Steven Weber*
|
24
|
+
|
25
|
+
* Reset statement cache for association if `table_name` is changed.
|
26
|
+
|
27
|
+
Fixes #36453.
|
28
|
+
|
29
|
+
*Ryuta Kamizono*
|
30
|
+
|
31
|
+
* Type cast extra select for eager loading.
|
32
|
+
|
33
|
+
*Ryuta Kamizono*
|
34
|
+
|
35
|
+
* Prevent collection associations from being autosaved multiple times.
|
36
|
+
|
37
|
+
Fixes #39173.
|
38
|
+
|
39
|
+
*Eugene Kenny*
|
40
|
+
|
41
|
+
* Resolve issue with insert_all unique_by option when used with expression index.
|
42
|
+
|
43
|
+
When the `:unique_by` option of `ActiveRecord::Persistence.insert_all` and
|
44
|
+
`ActiveRecord::Persistence.upsert_all` was used with the name of an expression index, an error
|
45
|
+
was raised. Adding a guard around the formatting behavior for the `:unique_by` corrects this.
|
46
|
+
|
47
|
+
Usage:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
create_table :books, id: :integer, force: true do |t|
|
51
|
+
t.column :name, :string
|
52
|
+
t.index "lower(name)", unique: true
|
53
|
+
end
|
54
|
+
|
55
|
+
Book.insert_all [{ name: "MyTest" }], unique_by: :index_books_on_lower_name
|
56
|
+
```
|
57
|
+
|
58
|
+
Fixes #39516.
|
59
|
+
|
60
|
+
*Austen Madden*
|
61
|
+
|
62
|
+
* Fix preloading for polymorphic association with custom scope.
|
63
|
+
|
64
|
+
*Ryuta Kamizono*
|
65
|
+
|
66
|
+
* Allow relations with different SQL comments in the `or` method.
|
67
|
+
|
68
|
+
*Takumi Shotoku*
|
69
|
+
|
70
|
+
* Resolve conflict between counter cache and optimistic locking.
|
71
|
+
|
72
|
+
Bump an Active Record instance's lock version after updating its counter
|
73
|
+
cache. This avoids raising an unnecessary `ActiveRecord::StaleObjectError`
|
74
|
+
upon subsequent transactions by maintaining parity with the corresponding
|
75
|
+
database record's `lock_version` column.
|
76
|
+
|
77
|
+
Fixes #16449.
|
78
|
+
|
79
|
+
*Aaron Lipman*
|
80
|
+
|
81
|
+
* Fix through association with source/through scope which has joins.
|
82
|
+
|
83
|
+
*Ryuta Kamizono*
|
84
|
+
|
85
|
+
* Fix through association to respect source scope for includes/preload.
|
86
|
+
|
87
|
+
*Ryuta Kamizono*
|
88
|
+
|
89
|
+
* Fix eager load with Arel joins to maintain the original joins order.
|
90
|
+
|
91
|
+
*Ryuta Kamizono*
|
92
|
+
|
93
|
+
* Fix group by count with eager loading + order + limit/offset.
|
94
|
+
|
95
|
+
*Ryuta Kamizono*
|
96
|
+
|
97
|
+
* Fix left joins order when merging multiple left joins from different associations.
|
98
|
+
|
99
|
+
*Ryuta Kamizono*
|
100
|
+
|
101
|
+
* Fix index creation to preserve index comment in bulk change table on MySQL.
|
102
|
+
|
103
|
+
*Ryuta Kamizono*
|
104
|
+
|
105
|
+
* Change `remove_foreign_key` to not check `:validate` option if database
|
106
|
+
doesn't support the feature.
|
107
|
+
|
108
|
+
*Ryuta Kamizono*
|
109
|
+
|
110
|
+
* Fix the result of aggregations to maintain duplicated "group by" fields.
|
111
|
+
|
112
|
+
*Ryuta Kamizono*
|
113
|
+
|
114
|
+
* Do not return duplicated records when using preload.
|
115
|
+
|
116
|
+
*Bogdan Gusiev*
|
117
|
+
|
118
|
+
|
119
|
+
## Rails 6.0.3.7 (May 05, 2021) ##
|
120
|
+
|
121
|
+
* No changes.
|
122
|
+
|
123
|
+
|
1
124
|
## Rails 6.0.3.6 (March 26, 2021) ##
|
2
125
|
|
3
126
|
* 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"
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
# == Callbacks
|
30
30
|
#
|
31
31
|
# Association with autosave option defines several callbacks on your
|
32
|
-
# model (before_save, after_create, after_update). Please note that
|
32
|
+
# model (around_save, before_save, after_create, after_update). Please note that
|
33
33
|
# callbacks are executed in the order they were defined in
|
34
34
|
# model. You should avoid modifying the association content, before
|
35
35
|
# autosave callbacks are executed. Placing your callbacks after
|
@@ -180,8 +180,7 @@ module ActiveRecord
|
|
180
180
|
save_method = :"autosave_associated_records_for_#{reflection.name}"
|
181
181
|
|
182
182
|
if reflection.collection?
|
183
|
-
|
184
|
-
after_save :after_save_collection_association
|
183
|
+
around_save :around_save_collection_association
|
185
184
|
|
186
185
|
define_non_cyclic_method(save_method) { save_collection_association(reflection) }
|
187
186
|
# Doesn't use after_save as that would save associations added in after_create/after_update twice
|
@@ -358,14 +357,15 @@ module ActiveRecord
|
|
358
357
|
end
|
359
358
|
end
|
360
359
|
|
361
|
-
# Is used as
|
360
|
+
# Is used as an around_save callback to check while saving a collection
|
362
361
|
# association whether or not the parent was a new record before saving.
|
363
|
-
def
|
364
|
-
@new_record_before_save ||=
|
365
|
-
|
362
|
+
def around_save_collection_association
|
363
|
+
previously_new_record_before_save = (@new_record_before_save ||= false)
|
364
|
+
@new_record_before_save = !previously_new_record_before_save && new_record?
|
366
365
|
|
367
|
-
|
368
|
-
|
366
|
+
yield
|
367
|
+
ensure
|
368
|
+
@new_record_before_save = previously_new_record_before_save
|
369
369
|
end
|
370
370
|
|
371
371
|
# Saves any new associated records, or all loaded autosave associations if
|
@@ -444,7 +444,7 @@ module ActiveRecord
|
|
444
444
|
unless reflection.through_reflection
|
445
445
|
record[reflection.foreign_key] = key
|
446
446
|
if inverse_reflection = reflection.inverse_of
|
447
|
-
record.association(inverse_reflection.name).
|
447
|
+
record.association(inverse_reflection.name).inversed_from(self)
|
448
448
|
end
|
449
449
|
end
|
450
450
|
|
@@ -1035,6 +1035,12 @@ module ActiveRecord
|
|
1035
1035
|
# In some cases you may want to prevent writes to the database
|
1036
1036
|
# even if you are on a database that can write. `while_preventing_writes`
|
1037
1037
|
# will prevent writes to the database for the duration of the block.
|
1038
|
+
#
|
1039
|
+
# This method does not provide the same protection as a readonly
|
1040
|
+
# user and is meant to be a safeguard against accidental writes.
|
1041
|
+
#
|
1042
|
+
# See `READ_QUERY` for the queries that are blocked by this
|
1043
|
+
# method.
|
1038
1044
|
def while_preventing_writes(enabled = true)
|
1039
1045
|
original, self.prevent_writes = self.prevent_writes, enabled
|
1040
1046
|
yield
|
@@ -63,6 +63,10 @@ module ActiveRecord
|
|
63
63
|
end
|
64
64
|
CODE
|
65
65
|
end
|
66
|
+
|
67
|
+
def aliased_types(name, fallback)
|
68
|
+
"timestamp" == name ? :datetime : fallback
|
69
|
+
end
|
66
70
|
end
|
67
71
|
|
68
72
|
AddColumnDefinition = Struct.new(:column) # :nodoc:
|
@@ -105,8 +109,9 @@ module ActiveRecord
|
|
105
109
|
!ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
|
106
110
|
end
|
107
111
|
|
108
|
-
def defined_for?(to_table: nil, **options)
|
112
|
+
def defined_for?(to_table: nil, validate: nil, **options)
|
109
113
|
(to_table.nil? || to_table.to_s == self.to_table) &&
|
114
|
+
(validate.nil? || validate == options.fetch(:validate, validate)) &&
|
110
115
|
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
111
116
|
end
|
112
117
|
|
@@ -103,7 +103,11 @@ module ActiveRecord
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
+
DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
|
107
|
+
private_constant :DEFAULT_READ_QUERY
|
108
|
+
|
106
109
|
def self.build_read_query_regexp(*parts) # :nodoc:
|
110
|
+
parts += DEFAULT_READ_QUERY
|
107
111
|
parts = parts.map { |part| /#{part}/i }
|
108
112
|
/\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
|
109
113
|
end
|
@@ -168,6 +172,8 @@ module ActiveRecord
|
|
168
172
|
spec_name = conn.pool.spec.name
|
169
173
|
name = "#{spec_name}::SchemaMigration"
|
170
174
|
|
175
|
+
return ActiveRecord::SchemaMigration if spec_name == "primary"
|
176
|
+
|
171
177
|
Class.new(ActiveRecord::SchemaMigration) do
|
172
178
|
define_singleton_method(:name) { name }
|
173
179
|
define_singleton_method(:to_s) { name }
|
@@ -675,9 +675,10 @@ module ActiveRecord
|
|
675
675
|
end
|
676
676
|
|
677
677
|
def add_index_for_alter(table_name, column_name, options = {})
|
678
|
-
index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, **options)
|
678
|
+
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, **options)
|
679
679
|
index_algorithm[0, 0] = ", " if index_algorithm.present?
|
680
|
-
"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
680
|
+
sql = +"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
681
|
+
add_sql_comment!(sql, comment)
|
681
682
|
end
|
682
683
|
|
683
684
|
def remove_index_for_alter(table_name, options = {})
|
@@ -686,7 +687,11 @@ module ActiveRecord
|
|
686
687
|
end
|
687
688
|
|
688
689
|
def supports_rename_index?
|
689
|
-
mariadb?
|
690
|
+
if mariadb?
|
691
|
+
database_version >= "10.5.2"
|
692
|
+
else
|
693
|
+
database_version >= "5.7.6"
|
694
|
+
end
|
690
695
|
end
|
691
696
|
|
692
697
|
def configure_connection
|
@@ -739,7 +744,7 @@ module ActiveRecord
|
|
739
744
|
end.compact.join(", ")
|
740
745
|
|
741
746
|
# ...and send them all in one query
|
742
|
-
execute
|
747
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
743
748
|
end
|
744
749
|
|
745
750
|
def column_definitions(table_name) # :nodoc:
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
end
|
21
21
|
|
22
22
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
23
|
-
:
|
23
|
+
:desc, :describe, :set, :show, :use
|
24
24
|
) # :nodoc:
|
25
25
|
private_constant :READ_QUERY
|
26
26
|
|
@@ -203,10 +203,14 @@ module ActiveRecord
|
|
203
203
|
def data_source_sql(name = nil, type: nil)
|
204
204
|
scope = quoted_scope(name, type: type)
|
205
205
|
|
206
|
-
sql = +"SELECT table_name FROM information_schema.tables"
|
207
|
-
sql << " WHERE table_schema = #{scope[:schema]}"
|
208
|
-
|
209
|
-
|
206
|
+
sql = +"SELECT table_name FROM (SELECT * FROM information_schema.tables "
|
207
|
+
sql << " WHERE table_schema = #{scope[:schema]}) _subquery"
|
208
|
+
if scope[:type] || scope[:name]
|
209
|
+
conditions = []
|
210
|
+
conditions << "_subquery.table_type = #{scope[:type]}" if scope[:type]
|
211
|
+
conditions << "_subquery.table_name = #{scope[:name]}" if scope[:name]
|
212
|
+
sql << " WHERE #{conditions.join(" AND ")}"
|
213
|
+
end
|
210
214
|
sql
|
211
215
|
end
|
212
216
|
|
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
end
|
69
69
|
|
70
70
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
71
|
-
:
|
71
|
+
:close, :declare, :fetch, :move, :set, :show
|
72
72
|
) # :nodoc:
|
73
73
|
private_constant :READ_QUERY
|
74
74
|
|
@@ -16,6 +16,14 @@ module ActiveRecord
|
|
16
16
|
super
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def type_cast_for_schema(value)
|
21
|
+
case value
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
24
|
+
else super
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|