activerecord 5.2.0 → 5.2.1
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 +65 -0
- data/lib/active_record/associations.rb +9 -9
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +17 -10
- data/lib/active_record/associations/belongs_to_association.rb +14 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
- data/lib/active_record/associations/builder/belongs_to.rb +11 -2
- data/lib/active_record/associations/collection_association.rb +10 -7
- data/lib/active_record/associations/has_many_through_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +8 -0
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency.rb +39 -64
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -18
- data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
- data/lib/active_record/associations/singular_association.rb +4 -10
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/autosave_association.rb +8 -3
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +0 -11
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -3
- data/lib/active_record/counter_cache.rb +17 -13
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/query_cache.rb +4 -11
- data/lib/active_record/relation.rb +13 -13
- data/lib/active_record/relation/finder_methods.rb +2 -4
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder.rb +6 -5
- data/lib/active_record/relation/query_methods.rb +16 -13
- data/lib/active_record/timestamp.rb +8 -1
- data/lib/active_record/transactions.rb +23 -20
- data/lib/active_record/type/serialized.rb +4 -0
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b480ac3395548916f9d2dd47e4b26eebab5e415cf32b51e7632bad78bf22dce9
|
4
|
+
data.tar.gz: 2f07a2153ae96236fcabe811139a9660273acff5bc042ed586934b4cb7207e45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a10d5aafe0fda079ccdeba3830674496e504c20549bb271df72cc099f63cdf10765766c13e30830b2960df7527a6aa3f499856e81e1f6baff74b61221f5c301c
|
7
|
+
data.tar.gz: 5509181237ce0872ecb1662b4a31cb7ef5c85b66fe9626e6bad9869e76b9649b8bb3c3f4e91bdf31aea86ae86174a6c83da2fcfc4df2622eddbb628fc0ca3d1c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,68 @@
|
|
1
|
+
## Rails 5.2.1 (August 07, 2018) ##
|
2
|
+
|
3
|
+
* PostgreSQL: Support new relkind for partitioned tables.
|
4
|
+
|
5
|
+
Fixes #33008.
|
6
|
+
|
7
|
+
*Yannick Schutz*
|
8
|
+
|
9
|
+
* Rollback parent transaction when children fails to update.
|
10
|
+
|
11
|
+
*Guillaume Malette*
|
12
|
+
|
13
|
+
* Fix default value for MySQL time types with specified precision.
|
14
|
+
|
15
|
+
*Nikolay Kondratyev*
|
16
|
+
|
17
|
+
* Fix `touch` option to behave consistently with `Persistence#touch` method.
|
18
|
+
|
19
|
+
*Ryuta Kamizono*
|
20
|
+
|
21
|
+
* Fix `save` in `after_create_commit` won't invoke extra `after_create_commit`.
|
22
|
+
|
23
|
+
Fixes #32831.
|
24
|
+
|
25
|
+
*Ryuta Kamizono*
|
26
|
+
|
27
|
+
* Fix logic on disabling commit callbacks so they are not called unexpectedly when errors occur.
|
28
|
+
|
29
|
+
*Brian Durand*
|
30
|
+
|
31
|
+
* Fix parent record should not get saved with duplicate children records.
|
32
|
+
|
33
|
+
Fixes #32940.
|
34
|
+
|
35
|
+
*Santosh Wadghule*
|
36
|
+
|
37
|
+
* Fix that association's after_touch is not called with counter cache.
|
38
|
+
|
39
|
+
Fixes #31559.
|
40
|
+
|
41
|
+
*Ryuta Kamizono*
|
42
|
+
|
43
|
+
* `becomes` should clear the mutation tracker which is created in `after_initialize`.
|
44
|
+
|
45
|
+
Fixes #32867.
|
46
|
+
|
47
|
+
*Ryuta Kamizono*
|
48
|
+
|
49
|
+
* Allow a belonging to parent object to be created from a new record.
|
50
|
+
|
51
|
+
*Jolyon Pawlyn*
|
52
|
+
|
53
|
+
* Fix that building record with assigning multiple has_one associations
|
54
|
+
wrongly persists through record.
|
55
|
+
|
56
|
+
Fixes #32511.
|
57
|
+
|
58
|
+
*Sam DeCesare*
|
59
|
+
|
60
|
+
* Fix relation merging when one of the relations is going to skip the
|
61
|
+
query cache.
|
62
|
+
|
63
|
+
*James Williams*
|
64
|
+
|
65
|
+
|
1
66
|
## Rails 5.2.0 (April 09, 2018) ##
|
2
67
|
|
3
68
|
* MySQL: Support mysql2 0.5.x.
|
@@ -241,7 +241,7 @@ module ActiveRecord
|
|
241
241
|
association
|
242
242
|
end
|
243
243
|
|
244
|
-
def association_cached?(name) # :nodoc
|
244
|
+
def association_cached?(name) # :nodoc:
|
245
245
|
@association_cache.key?(name)
|
246
246
|
end
|
247
247
|
|
@@ -1232,9 +1232,9 @@ module ActiveRecord
|
|
1232
1232
|
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
|
1233
1233
|
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
|
1234
1234
|
# * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
|
1235
|
-
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new(
|
1236
|
-
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new(
|
1237
|
-
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new(
|
1235
|
+
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new(firm_id: id)</tt>)
|
1236
|
+
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new(firm_id: id); c.save; c</tt>)
|
1237
|
+
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new(firm_id: id); c.save!</tt>)
|
1238
1238
|
# * <tt>Firm#clients.reload</tt>
|
1239
1239
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1240
1240
|
#
|
@@ -1405,9 +1405,9 @@ module ActiveRecord
|
|
1405
1405
|
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
1406
1406
|
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
|
1407
1407
|
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
|
1408
|
-
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new(
|
1409
|
-
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new(
|
1410
|
-
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new(
|
1408
|
+
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new(account_id: id)</tt>)
|
1409
|
+
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new(account_id: id); b.save; b</tt>)
|
1410
|
+
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new(account_id: id); b.save!; b</tt>)
|
1411
1411
|
# * <tt>Account#reload_beneficiary</tt>
|
1412
1412
|
#
|
1413
1413
|
# === Scopes
|
@@ -1746,8 +1746,8 @@ module ActiveRecord
|
|
1746
1746
|
# * <tt>Developer#projects.size</tt>
|
1747
1747
|
# * <tt>Developer#projects.find(id)</tt>
|
1748
1748
|
# * <tt>Developer#projects.exists?(...)</tt>
|
1749
|
-
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new(
|
1750
|
-
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new(
|
1749
|
+
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new(developer_id: id)</tt>)
|
1750
|
+
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new(developer_id: id); c.save; c</tt>)
|
1751
1751
|
# * <tt>Developer#projects.reload</tt>
|
1752
1752
|
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
1753
1753
|
#
|
@@ -19,7 +19,6 @@ module ActiveRecord
|
|
19
19
|
# HasManyThroughAssociation + ThroughAssociation
|
20
20
|
class Association #:nodoc:
|
21
21
|
attr_reader :owner, :target, :reflection
|
22
|
-
attr_accessor :inversed
|
23
22
|
|
24
23
|
delegate :options, to: :reflection
|
25
24
|
|
@@ -67,7 +66,7 @@ module ActiveRecord
|
|
67
66
|
#
|
68
67
|
# Note that if the target has not been loaded, it is not considered stale.
|
69
68
|
def stale_target?
|
70
|
-
|
69
|
+
!@inversed && loaded? && @stale_state != stale_state
|
71
70
|
end
|
72
71
|
|
73
72
|
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
|
@@ -98,23 +97,24 @@ module ActiveRecord
|
|
98
97
|
|
99
98
|
# Set the inverse association, if possible
|
100
99
|
def set_inverse_instance(record)
|
101
|
-
if
|
102
|
-
inverse
|
103
|
-
inverse.target = owner
|
104
|
-
inverse.inversed = true
|
100
|
+
if inverse = inverse_association_for(record)
|
101
|
+
inverse.inversed_from(owner)
|
105
102
|
end
|
106
103
|
record
|
107
104
|
end
|
108
105
|
|
109
106
|
# Remove the inverse association, if possible
|
110
107
|
def remove_inverse_instance(record)
|
111
|
-
if
|
112
|
-
inverse
|
113
|
-
inverse.target = nil
|
114
|
-
inverse.inversed = false
|
108
|
+
if inverse = inverse_association_for(record)
|
109
|
+
inverse.inversed_from(nil)
|
115
110
|
end
|
116
111
|
end
|
117
112
|
|
113
|
+
def inversed_from(record)
|
114
|
+
self.target = record
|
115
|
+
@inversed = !!record
|
116
|
+
end
|
117
|
+
|
118
118
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
119
119
|
# polymorphic_type field on the owner.
|
120
120
|
def klass
|
@@ -240,6 +240,12 @@ module ActiveRecord
|
|
240
240
|
end
|
241
241
|
end
|
242
242
|
|
243
|
+
def inverse_association_for(record)
|
244
|
+
if invertible_for?(record)
|
245
|
+
record.association(inverse_reflection_for(record).name)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
243
249
|
# Can be redefined by subclasses, notably polymorphic belongs_to
|
244
250
|
# The record parameter is necessary to support polymorphic inverses as we must check for
|
245
251
|
# the association in the specific class of the record.
|
@@ -269,6 +275,7 @@ module ActiveRecord
|
|
269
275
|
def build_record(attributes)
|
270
276
|
reflection.build_association(attributes) do |record|
|
271
277
|
initialize_attributes(record, attributes)
|
278
|
+
yield(record) if block_given?
|
272
279
|
end
|
273
280
|
end
|
274
281
|
|
@@ -26,10 +26,12 @@ module ActiveRecord
|
|
26
26
|
decrement_counters
|
27
27
|
end
|
28
28
|
|
29
|
+
replace_keys(record)
|
30
|
+
|
29
31
|
self.target = record
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
34
|
+
def inversed_from(record)
|
33
35
|
replace_keys(record)
|
34
36
|
super
|
35
37
|
end
|
@@ -55,6 +57,10 @@ module ActiveRecord
|
|
55
57
|
update_counters(1)
|
56
58
|
end
|
57
59
|
|
60
|
+
def target_changed?
|
61
|
+
owner.saved_change_to_attribute?(reflection.foreign_key)
|
62
|
+
end
|
63
|
+
|
58
64
|
private
|
59
65
|
|
60
66
|
def update_counters(by)
|
@@ -78,19 +84,22 @@ module ActiveRecord
|
|
78
84
|
def update_counters_on_replace(record)
|
79
85
|
if require_counter_update? && different_target?(record)
|
80
86
|
owner.instance_variable_set :@_after_replace_counter_called, true
|
81
|
-
record.increment!(reflection.counter_cache_column)
|
87
|
+
record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
|
82
88
|
decrement_counters
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
86
92
|
# Checks whether record is different to the current target, without loading it
|
87
93
|
def different_target?(record)
|
88
|
-
record.
|
94
|
+
record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
|
89
95
|
end
|
90
96
|
|
91
97
|
def replace_keys(record)
|
92
|
-
owner[reflection.foreign_key] = record ?
|
93
|
-
|
98
|
+
owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def primary_key(record)
|
102
|
+
reflection.association_primary_key(record.class)
|
94
103
|
end
|
95
104
|
|
96
105
|
def foreign_key_present?
|
@@ -9,8 +9,11 @@ module ActiveRecord
|
|
9
9
|
type.presence && type.constantize
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
def target_changed?
|
13
|
+
super || owner.saved_change_to_attribute?(reflection.foreign_type)
|
14
|
+
end
|
13
15
|
|
16
|
+
private
|
14
17
|
def replace_keys(record)
|
15
18
|
super
|
16
19
|
owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
|
@@ -36,7 +36,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
36
36
|
|
37
37
|
if (@_after_replace_counter_called ||= false)
|
38
38
|
@_after_replace_counter_called = false
|
39
|
-
elsif
|
39
|
+
elsif association(reflection.name).target_changed?
|
40
40
|
if reflection.polymorphic?
|
41
41
|
model = attribute_in_database(reflection.foreign_type).try(:constantize)
|
42
42
|
model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
|
@@ -49,14 +49,22 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
49
49
|
foreign_key = attribute_in_database foreign_key
|
50
50
|
|
51
51
|
if foreign_key && model.respond_to?(:increment_counter)
|
52
|
+
foreign_key = counter_cache_target(reflection, model, foreign_key)
|
52
53
|
model.increment_counter(cache_column, foreign_key)
|
53
54
|
end
|
54
55
|
|
55
56
|
if foreign_key_was && model_was.respond_to?(:decrement_counter)
|
57
|
+
foreign_key_was = counter_cache_target(reflection, model_was, foreign_key_was)
|
56
58
|
model_was.decrement_counter(cache_column, foreign_key_was)
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def counter_cache_target(reflection, model, foreign_key)
|
65
|
+
primary_key = reflection.association_primary_key(model)
|
66
|
+
model.unscoped.where!(primary_key => foreign_key)
|
67
|
+
end
|
60
68
|
end
|
61
69
|
end
|
62
70
|
|
@@ -84,7 +92,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
84
92
|
else
|
85
93
|
klass = association.klass
|
86
94
|
end
|
87
|
-
|
95
|
+
primary_key = reflection.association_primary_key(klass)
|
96
|
+
old_record = klass.find_by(primary_key => old_foreign_id)
|
88
97
|
|
89
98
|
if old_record
|
90
99
|
if touch != true
|
@@ -103,9 +103,7 @@ module ActiveRecord
|
|
103
103
|
if attributes.is_a?(Array)
|
104
104
|
attributes.collect { |attr| build(attr, &block) }
|
105
105
|
else
|
106
|
-
add_to_target(build_record(attributes))
|
107
|
-
yield(record) if block_given?
|
108
|
-
end
|
106
|
+
add_to_target(build_record(attributes, &block))
|
109
107
|
end
|
110
108
|
end
|
111
109
|
|
@@ -356,15 +354,18 @@ module ActiveRecord
|
|
356
354
|
if attributes.is_a?(Array)
|
357
355
|
attributes.collect { |attr| _create_record(attr, raise, &block) }
|
358
356
|
else
|
357
|
+
record = build_record(attributes, &block)
|
359
358
|
transaction do
|
360
|
-
|
361
|
-
|
362
|
-
insert_record(record, true, raise) {
|
359
|
+
result = nil
|
360
|
+
add_to_target(record) do
|
361
|
+
result = insert_record(record, true, raise) {
|
363
362
|
@_was_loaded = loaded?
|
364
363
|
@association_ids = nil
|
365
364
|
}
|
366
365
|
end
|
366
|
+
raise ActiveRecord::Rollback unless result
|
367
367
|
end
|
368
|
+
record
|
368
369
|
end
|
369
370
|
end
|
370
371
|
|
@@ -442,7 +443,9 @@ module ActiveRecord
|
|
442
443
|
end
|
443
444
|
end
|
444
445
|
|
445
|
-
|
446
|
+
raise ActiveRecord::Rollback unless result
|
447
|
+
|
448
|
+
records
|
446
449
|
end
|
447
450
|
|
448
451
|
def replace_on_target(record, index, skip_callbacks)
|
@@ -107,6 +107,14 @@ module ActiveRecord
|
|
107
107
|
yield
|
108
108
|
end
|
109
109
|
end
|
110
|
+
|
111
|
+
def _create_record(attributes, raise_error = false, &block)
|
112
|
+
unless owner.persisted?
|
113
|
+
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
114
|
+
end
|
115
|
+
|
116
|
+
super
|
117
|
+
end
|
110
118
|
end
|
111
119
|
end
|
112
120
|
end
|
@@ -28,7 +28,11 @@ module ActiveRecord
|
|
28
28
|
end
|
29
29
|
|
30
30
|
if through_record
|
31
|
-
through_record.
|
31
|
+
if through_record.new_record?
|
32
|
+
through_record.assign_attributes(attributes)
|
33
|
+
else
|
34
|
+
through_record.update(attributes)
|
35
|
+
end
|
32
36
|
elsif owner.new_record? || !save
|
33
37
|
through_proxy.build(attributes)
|
34
38
|
else
|
@@ -67,63 +67,31 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
# associations is the list of associations which are joined using hash, symbol or array.
|
72
|
-
# joins is the list of all string join commands and arel nodes.
|
73
|
-
#
|
74
|
-
# Example :
|
75
|
-
#
|
76
|
-
# class Physician < ActiveRecord::Base
|
77
|
-
# has_many :appointments
|
78
|
-
# has_many :patients, through: :appointments
|
79
|
-
# end
|
80
|
-
#
|
81
|
-
# If I execute `@physician.patients.to_a` then
|
82
|
-
# base # => Physician
|
83
|
-
# associations # => []
|
84
|
-
# joins # => [#<Arel::Nodes::InnerJoin: ...]
|
85
|
-
#
|
86
|
-
# However if I execute `Physician.joins(:appointments).to_a` then
|
87
|
-
# base # => Physician
|
88
|
-
# associations # => [:appointments]
|
89
|
-
# joins # => []
|
90
|
-
#
|
91
|
-
def initialize(base, table, associations, alias_tracker)
|
92
|
-
@alias_tracker = alias_tracker
|
70
|
+
def initialize(base, table, associations)
|
93
71
|
tree = self.class.make_tree associations
|
94
72
|
@join_root = JoinBase.new(base, table, build(tree, base))
|
95
|
-
@join_root.children.each { |child| construct_tables! @join_root, child }
|
96
73
|
end
|
97
74
|
|
98
75
|
def reflections
|
99
76
|
join_root.drop(1).map!(&:reflection)
|
100
77
|
end
|
101
78
|
|
102
|
-
def join_constraints(joins_to_add, join_type)
|
103
|
-
|
104
|
-
|
105
|
-
|
79
|
+
def join_constraints(joins_to_add, join_type, alias_tracker)
|
80
|
+
@alias_tracker = alias_tracker
|
81
|
+
|
82
|
+
construct_tables!(join_root)
|
83
|
+
joins = make_join_constraints(join_root, join_type)
|
106
84
|
|
107
85
|
joins.concat joins_to_add.flat_map { |oj|
|
86
|
+
construct_tables!(oj.join_root)
|
108
87
|
if join_root.match? oj.join_root
|
109
88
|
walk join_root, oj.join_root
|
110
89
|
else
|
111
|
-
oj.join_root
|
112
|
-
make_join_constraints(oj.join_root, child, join_type)
|
113
|
-
}
|
90
|
+
make_join_constraints(oj.join_root, join_type)
|
114
91
|
end
|
115
92
|
}
|
116
93
|
end
|
117
94
|
|
118
|
-
def aliases
|
119
|
-
@aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
|
120
|
-
columns = join_part.column_names.each_with_index.map { |column_name, j|
|
121
|
-
Aliases::Column.new column_name, "t#{i}_r#{j}"
|
122
|
-
}
|
123
|
-
Aliases::Table.new(join_part, columns)
|
124
|
-
}
|
125
|
-
end
|
126
|
-
|
127
95
|
def instantiate(result_set, &block)
|
128
96
|
primary_key = aliases.column_alias(join_root, join_root.primary_key)
|
129
97
|
|
@@ -155,28 +123,40 @@ module ActiveRecord
|
|
155
123
|
parents.values
|
156
124
|
end
|
157
125
|
|
126
|
+
def apply_column_aliases(relation)
|
127
|
+
relation._select!(-> { aliases.columns })
|
128
|
+
end
|
129
|
+
|
158
130
|
protected
|
159
|
-
attr_reader :alias_tracker, :
|
131
|
+
attr_reader :alias_tracker, :join_root
|
160
132
|
|
161
133
|
private
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
134
|
+
def aliases
|
135
|
+
@aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
|
136
|
+
columns = join_part.column_names.each_with_index.map { |column_name, j|
|
137
|
+
Aliases::Column.new column_name, "t#{i}_r#{j}"
|
138
|
+
}
|
139
|
+
Aliases::Table.new(join_part, columns)
|
140
|
+
}
|
168
141
|
end
|
169
142
|
|
170
|
-
def
|
171
|
-
|
172
|
-
|
143
|
+
def construct_tables!(join_root)
|
144
|
+
join_root.each_children do |parent, child|
|
145
|
+
child.tables = table_aliases_for(parent, child)
|
146
|
+
end
|
173
147
|
end
|
174
148
|
|
175
|
-
def make_join_constraints(
|
176
|
-
|
177
|
-
|
149
|
+
def make_join_constraints(join_root, join_type)
|
150
|
+
join_root.children.flat_map do |child|
|
151
|
+
make_constraints(join_root, child, join_type)
|
152
|
+
end
|
153
|
+
end
|
178
154
|
|
179
|
-
|
155
|
+
def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin)
|
156
|
+
foreign_table = parent.table
|
157
|
+
foreign_klass = parent.base_klass
|
158
|
+
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
159
|
+
joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
180
160
|
end
|
181
161
|
|
182
162
|
def table_aliases_for(parent, node)
|
@@ -189,11 +169,6 @@ module ActiveRecord
|
|
189
169
|
}
|
190
170
|
end
|
191
171
|
|
192
|
-
def construct_tables!(parent, node)
|
193
|
-
node.tables = table_aliases_for(parent, node)
|
194
|
-
node.children.each { |child| construct_tables! node, child }
|
195
|
-
end
|
196
|
-
|
197
172
|
def table_alias_for(reflection, parent, join)
|
198
173
|
name = "#{reflection.plural_name}_#{parent.table_name}"
|
199
174
|
join ? "#{name}_join" : name
|
@@ -204,8 +179,8 @@ module ActiveRecord
|
|
204
179
|
[left.children.find { |node2| node1.match? node2 }, node1]
|
205
180
|
}.partition(&:first)
|
206
181
|
|
207
|
-
|
208
|
-
|
182
|
+
joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r) }
|
183
|
+
joins.concat missing.flat_map { |_, n| make_constraints(left, n) }
|
209
184
|
end
|
210
185
|
|
211
186
|
def find_reflection(klass, name)
|
@@ -223,7 +198,7 @@ module ActiveRecord
|
|
223
198
|
raise EagerLoadPolymorphicError.new(reflection)
|
224
199
|
end
|
225
200
|
|
226
|
-
JoinAssociation.new(reflection, build(right, reflection.klass)
|
201
|
+
JoinAssociation.new(reflection, build(right, reflection.klass))
|
227
202
|
end
|
228
203
|
end
|
229
204
|
|
@@ -248,7 +223,7 @@ module ActiveRecord
|
|
248
223
|
next
|
249
224
|
end
|
250
225
|
|
251
|
-
model = seen[ar_parent.object_id][node
|
226
|
+
model = seen[ar_parent.object_id][node][id]
|
252
227
|
|
253
228
|
if model
|
254
229
|
construct(model, node, row, rs, seen, model_cache, aliases)
|
@@ -260,7 +235,7 @@ module ActiveRecord
|
|
260
235
|
model.readonly!
|
261
236
|
end
|
262
237
|
|
263
|
-
seen[ar_parent.object_id][node
|
238
|
+
seen[ar_parent.object_id][node][id] = model
|
264
239
|
construct(model, node, row, rs, seen, model_cache, aliases)
|
265
240
|
end
|
266
241
|
end
|