activerecord 5.0.0.beta2 → 5.0.0.beta3
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 +83 -20
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -0
- data/lib/active_record/associations/collection_association.rb +12 -1
- data/lib/active_record/associations/collection_proxy.rb +14 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -7
- data/lib/active_record/associations/preloader/association.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +0 -8
- data/lib/active_record/attribute_methods.rb +0 -24
- data/lib/active_record/attribute_methods/read.rb +5 -17
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -2
- data/lib/active_record/attribute_methods/write.rb +0 -13
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -2
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +4 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1 -2
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +10 -16
- data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +3 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -1
- data/lib/active_record/core.rb +5 -0
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +1 -1
- data/lib/active_record/nested_attributes.rb +14 -6
- data/lib/active_record/null_relation.rb +1 -1
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/reflection.rb +53 -36
- data/lib/active_record/relation.rb +26 -18
- data/lib/active_record/relation/batches.rb +4 -4
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/calculations.rb +2 -10
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +55 -26
- data/lib/active_record/relation/predicate_builder.rb +3 -4
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +10 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +11 -7
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/sanitization.rb +1 -1
- data/lib/active_record/schema_dumper.rb +6 -4
- data/lib/active_record/scoping/named.rb +10 -0
- data/lib/active_record/statement_cache.rb +1 -1
- data/lib/active_record/table_metadata.rb +5 -1
- data/lib/active_record/tasks/database_tasks.rb +4 -0
- data/lib/active_record/validations.rb +1 -1
- data/lib/active_record/validations/absence.rb +0 -1
- data/lib/active_record/validations/length.rb +0 -12
- data/lib/active_record/validations/presence.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +7 -9
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -0
- data/lib/rails/generators/active_record/model/templates/application_record.rb +3 -0
- metadata +9 -8
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
47
47
|
|
48
48
|
if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
|
49
49
|
primary_key_value = connection.next_sequence_value(klass.sequence_name)
|
50
|
-
values[klass.
|
50
|
+
values[arel_attribute(klass.primary_key)] = primary_key_value
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -105,6 +105,10 @@ module ActiveRecord
|
|
105
105
|
[substitutes, binds]
|
106
106
|
end
|
107
107
|
|
108
|
+
def arel_attribute(name) # :nodoc:
|
109
|
+
klass.arel_attribute(name, table)
|
110
|
+
end
|
111
|
+
|
108
112
|
# Initializes new record from relation while maintaining the current
|
109
113
|
# scope.
|
110
114
|
#
|
@@ -249,17 +253,21 @@ module ActiveRecord
|
|
249
253
|
|
250
254
|
# Converts relation objects to Array.
|
251
255
|
def to_a
|
256
|
+
records.dup
|
257
|
+
end
|
258
|
+
|
259
|
+
def records # :nodoc:
|
252
260
|
load
|
253
261
|
@records
|
254
262
|
end
|
255
263
|
|
256
264
|
# Serializes the relation objects Array.
|
257
265
|
def encode_with(coder)
|
258
|
-
coder.represent_seq(nil,
|
266
|
+
coder.represent_seq(nil, records)
|
259
267
|
end
|
260
268
|
|
261
269
|
def as_json(options = nil) #:nodoc:
|
262
|
-
|
270
|
+
records.as_json(options)
|
263
271
|
end
|
264
272
|
|
265
273
|
# Returns size of the records.
|
@@ -294,13 +302,13 @@ module ActiveRecord
|
|
294
302
|
# Returns true if there is exactly one record.
|
295
303
|
def one?
|
296
304
|
return super if block_given?
|
297
|
-
limit_value ?
|
305
|
+
limit_value ? records.one? : size == 1
|
298
306
|
end
|
299
307
|
|
300
308
|
# Returns true if there is more than one record.
|
301
309
|
def many?
|
302
310
|
return super if block_given?
|
303
|
-
limit_value ?
|
311
|
+
limit_value ? records.many? : size > 1
|
304
312
|
end
|
305
313
|
|
306
314
|
# Returns a cache key that can be used to identify the records fetched by
|
@@ -373,9 +381,9 @@ module ActiveRecord
|
|
373
381
|
stmt.table(table)
|
374
382
|
|
375
383
|
if joins_values.any?
|
376
|
-
@klass.connection.join_to_update(stmt, arel,
|
384
|
+
@klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
|
377
385
|
else
|
378
|
-
stmt.key =
|
386
|
+
stmt.key = arel_attribute(primary_key)
|
379
387
|
stmt.take(arel.limit)
|
380
388
|
stmt.order(*arel.orders)
|
381
389
|
stmt.wheres = arel.constraints
|
@@ -414,7 +422,7 @@ module ActiveRecord
|
|
414
422
|
if id.is_a?(Array)
|
415
423
|
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
|
416
424
|
elsif id == :all
|
417
|
-
|
425
|
+
records.each { |record| record.update(attributes) }
|
418
426
|
else
|
419
427
|
if ActiveRecord::Base === id
|
420
428
|
id = id.id
|
@@ -453,7 +461,7 @@ module ActiveRecord
|
|
453
461
|
MESSAGE
|
454
462
|
where(conditions).destroy_all
|
455
463
|
else
|
456
|
-
|
464
|
+
records.each(&:destroy).tap { reset }
|
457
465
|
end
|
458
466
|
end
|
459
467
|
|
@@ -527,7 +535,7 @@ module ActiveRecord
|
|
527
535
|
stmt.from(table)
|
528
536
|
|
529
537
|
if joins_values.any?
|
530
|
-
@klass.connection.join_to_delete(stmt, arel,
|
538
|
+
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
|
531
539
|
else
|
532
540
|
stmt.wheres = arel.constraints
|
533
541
|
end
|
@@ -583,7 +591,7 @@ module ActiveRecord
|
|
583
591
|
def reset
|
584
592
|
@last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
|
585
593
|
@should_eager_load = @join_dependency = nil
|
586
|
-
@records = []
|
594
|
+
@records = [].freeze
|
587
595
|
@offsets = {}
|
588
596
|
self
|
589
597
|
end
|
@@ -650,21 +658,21 @@ module ActiveRecord
|
|
650
658
|
def ==(other)
|
651
659
|
case other
|
652
660
|
when Associations::CollectionProxy, AssociationRelation
|
653
|
-
self == other.
|
661
|
+
self == other.records
|
654
662
|
when Relation
|
655
663
|
other.to_sql == to_sql
|
656
664
|
when Array
|
657
|
-
|
665
|
+
records == other
|
658
666
|
end
|
659
667
|
end
|
660
668
|
|
661
669
|
def pretty_print(q)
|
662
|
-
q.pp(self.
|
670
|
+
q.pp(self.records)
|
663
671
|
end
|
664
672
|
|
665
673
|
# Returns true if relation is blank.
|
666
674
|
def blank?
|
667
|
-
|
675
|
+
records.blank?
|
668
676
|
end
|
669
677
|
|
670
678
|
def values
|
@@ -672,7 +680,7 @@ module ActiveRecord
|
|
672
680
|
end
|
673
681
|
|
674
682
|
def inspect
|
675
|
-
entries =
|
683
|
+
entries = records.take([limit_value, 11].compact.min).map!(&:inspect)
|
676
684
|
entries[10] = '...' if entries.size == 11
|
677
685
|
|
678
686
|
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
@@ -681,14 +689,14 @@ module ActiveRecord
|
|
681
689
|
protected
|
682
690
|
|
683
691
|
def load_records(records)
|
684
|
-
@records = records
|
692
|
+
@records = records.freeze
|
685
693
|
@loaded = true
|
686
694
|
end
|
687
695
|
|
688
696
|
private
|
689
697
|
|
690
698
|
def exec_queries
|
691
|
-
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bound_attributes)
|
699
|
+
@records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
|
692
700
|
|
693
701
|
preload = preload_values
|
694
702
|
preload += includes_values unless eager_loading?
|
@@ -187,7 +187,7 @@ module ActiveRecord
|
|
187
187
|
|
188
188
|
loop do
|
189
189
|
if load
|
190
|
-
records = batch_relation.
|
190
|
+
records = batch_relation.records
|
191
191
|
ids = records.map(&:id)
|
192
192
|
yielded_relation = self.where(primary_key => ids)
|
193
193
|
yielded_relation.load_records(records)
|
@@ -204,15 +204,15 @@ module ActiveRecord
|
|
204
204
|
yield yielded_relation
|
205
205
|
|
206
206
|
break if ids.length < of
|
207
|
-
batch_relation = relation.where(
|
207
|
+
batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset))
|
208
208
|
end
|
209
209
|
end
|
210
210
|
|
211
211
|
private
|
212
212
|
|
213
213
|
def apply_limits(relation, start, finish)
|
214
|
-
relation = relation.where(
|
215
|
-
relation = relation.where(
|
214
|
+
relation = relation.where(arel_attribute(primary_key).gteq(start)) if start
|
215
|
+
relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish
|
216
216
|
relation
|
217
217
|
end
|
218
218
|
|
@@ -35,7 +35,7 @@ module ActiveRecord
|
|
35
35
|
return to_enum(:each_record) unless block_given?
|
36
36
|
|
37
37
|
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
|
38
|
-
relation.
|
38
|
+
relation.records.each { |record| yield record }
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -155,15 +155,7 @@ module ActiveRecord
|
|
155
155
|
# See also #ids.
|
156
156
|
#
|
157
157
|
def pluck(*column_names)
|
158
|
-
column_names.map
|
159
|
-
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
|
160
|
-
attribute_alias(column_name)
|
161
|
-
else
|
162
|
-
column_name.to_s
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
if loaded? && (column_names - @klass.column_names).empty?
|
158
|
+
if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
167
159
|
return @records.pluck(*column_names)
|
168
160
|
end
|
169
161
|
|
@@ -172,7 +164,7 @@ module ActiveRecord
|
|
172
164
|
else
|
173
165
|
relation = spawn
|
174
166
|
relation.select_values = column_names.map { |cn|
|
175
|
-
|
167
|
+
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
176
168
|
}
|
177
169
|
result = klass.connection.select_all(relation.arel, nil, bound_attributes)
|
178
170
|
result.cast_values(klass.attribute_types)
|
@@ -37,7 +37,8 @@ module ActiveRecord
|
|
37
37
|
# for each different klass, and the delegations are compiled into that subclass only.
|
38
38
|
|
39
39
|
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
|
40
|
-
|
40
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
41
|
+
:shuffle, :split, to: :records
|
41
42
|
|
42
43
|
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
43
44
|
:connection, :columns_hash, :to => :klass
|
@@ -145,15 +145,21 @@ module ActiveRecord
|
|
145
145
|
#
|
146
146
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
147
147
|
def last(limit = nil)
|
148
|
-
if
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
148
|
+
return find_last(limit) if loaded? || limit_value
|
149
|
+
|
150
|
+
result = limit(limit || 1)
|
151
|
+
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
|
152
|
+
result = result.reverse_order!
|
153
|
+
|
154
|
+
limit ? result.reverse : result.first
|
155
|
+
rescue ActiveRecord::IrreversibleOrderError
|
156
|
+
ActiveSupport::Deprecation.warn(<<-WARNING.squish)
|
157
|
+
Finding a last element by loading the relation when SQL ORDER
|
158
|
+
can not be reversed is deprecated.
|
159
|
+
Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
|
160
|
+
Please call `to_a.last` if you still want to load the relation.
|
161
|
+
WARNING
|
162
|
+
find_last(limit)
|
157
163
|
end
|
158
164
|
|
159
165
|
# Same as #last but raises ActiveRecord::RecordNotFound if no record
|
@@ -242,6 +248,38 @@ module ActiveRecord
|
|
242
248
|
find_nth! 41
|
243
249
|
end
|
244
250
|
|
251
|
+
# Find the third-to-last record.
|
252
|
+
# If no order is defined it will order by primary key.
|
253
|
+
#
|
254
|
+
# Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
|
255
|
+
# Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
|
256
|
+
# Person.where(["user_name = :u", { u: user_name }]).third_to_last
|
257
|
+
def third_to_last
|
258
|
+
find_nth(-3)
|
259
|
+
end
|
260
|
+
|
261
|
+
# Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
|
262
|
+
# is found.
|
263
|
+
def third_to_last!
|
264
|
+
find_nth!(-3)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Find the second-to-last record.
|
268
|
+
# If no order is defined it will order by primary key.
|
269
|
+
#
|
270
|
+
# Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
|
271
|
+
# Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
|
272
|
+
# Person.where(["user_name = :u", { u: user_name }]).second_to_last
|
273
|
+
def second_to_last
|
274
|
+
find_nth(-2)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
|
278
|
+
# is found.
|
279
|
+
def second_to_last!
|
280
|
+
find_nth!(-2)
|
281
|
+
end
|
282
|
+
|
245
283
|
# Returns true if a record exists in the table that matches the +id+ or
|
246
284
|
# conditions given, or false otherwise. The argument can take six forms:
|
247
285
|
#
|
@@ -298,7 +336,7 @@ module ActiveRecord
|
|
298
336
|
end
|
299
337
|
|
300
338
|
# This method is called whenever no records are found with either a single
|
301
|
-
# id or multiple ids and raises
|
339
|
+
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
302
340
|
#
|
303
341
|
# The error message is different depending on whether a single id or
|
304
342
|
# multiple ids are provided. If multiple ids are provided, then the number
|
@@ -468,7 +506,7 @@ module ActiveRecord
|
|
468
506
|
def find_some_ordered(ids)
|
469
507
|
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
470
508
|
|
471
|
-
result = except(:limit, :offset).where(primary_key => ids).
|
509
|
+
result = except(:limit, :offset).where(primary_key => ids).records
|
472
510
|
|
473
511
|
if result.size == ids.size
|
474
512
|
pk_type = @klass.type_for_attribute(primary_key)
|
@@ -484,7 +522,7 @@ module ActiveRecord
|
|
484
522
|
if loaded?
|
485
523
|
@records.first
|
486
524
|
else
|
487
|
-
@take ||= limit(1).
|
525
|
+
@take ||= limit(1).records.first
|
488
526
|
end
|
489
527
|
end
|
490
528
|
|
@@ -514,7 +552,7 @@ module ActiveRecord
|
|
514
552
|
# TODO: once the offset argument is removed from find_nth,
|
515
553
|
# find_nth_with_limit_and_offset can be merged into this method
|
516
554
|
relation = if order_values.empty? && primary_key
|
517
|
-
order(
|
555
|
+
order(arel_attribute(primary_key).asc)
|
518
556
|
else
|
519
557
|
self
|
520
558
|
end
|
@@ -523,19 +561,6 @@ module ActiveRecord
|
|
523
561
|
relation.limit(limit).to_a
|
524
562
|
end
|
525
563
|
|
526
|
-
def find_last
|
527
|
-
if loaded?
|
528
|
-
@records.last
|
529
|
-
else
|
530
|
-
@last ||=
|
531
|
-
if limit_value
|
532
|
-
to_a.last
|
533
|
-
else
|
534
|
-
reverse_order.limit(1).to_a.first
|
535
|
-
end
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
564
|
private
|
540
565
|
|
541
566
|
def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
|
@@ -546,5 +571,9 @@ module ActiveRecord
|
|
546
571
|
find_nth_with_limit(index, limit)
|
547
572
|
end
|
548
573
|
end
|
574
|
+
|
575
|
+
def find_last(limit)
|
576
|
+
limit ? records.last(limit) : records.last
|
577
|
+
end
|
549
578
|
end
|
550
579
|
end
|
@@ -5,6 +5,7 @@ module ActiveRecord
|
|
5
5
|
require 'active_record/relation/predicate_builder/base_handler'
|
6
6
|
require 'active_record/relation/predicate_builder/basic_object_handler'
|
7
7
|
require 'active_record/relation/predicate_builder/class_handler'
|
8
|
+
require 'active_record/relation/predicate_builder/polymorphic_array_handler'
|
8
9
|
require 'active_record/relation/predicate_builder/range_handler'
|
9
10
|
require 'active_record/relation/predicate_builder/relation_handler'
|
10
11
|
|
@@ -22,6 +23,7 @@ module ActiveRecord
|
|
22
23
|
register_handler(Relation, RelationHandler.new)
|
23
24
|
register_handler(Array, ArrayHandler.new(self))
|
24
25
|
register_handler(AssociationQueryValue, AssociationQueryHandler.new(self))
|
26
|
+
register_handler(PolymorphicArrayValue, PolymorphicArrayHandler.new(self))
|
25
27
|
end
|
26
28
|
|
27
29
|
def build_from_hash(attributes)
|
@@ -40,10 +42,7 @@ module ActiveRecord
|
|
40
42
|
#
|
41
43
|
# For polymorphic relationships, find the foreign key and type:
|
42
44
|
# PriceEstimate.where(estimate_of: treasure)
|
43
|
-
if table.associated_with?(column)
|
44
|
-
value = AssociationQueryValue.new(table.associated_table(column), value)
|
45
|
-
end
|
46
|
-
|
45
|
+
value = AssociationQueryHandler.value_for(table, column, value) if table.associated_with?(column)
|
47
46
|
build(table.arel_attribute(column), value)
|
48
47
|
end
|
49
48
|
|
@@ -1,6 +1,16 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
class PredicateBuilder
|
3
3
|
class AssociationQueryHandler # :nodoc:
|
4
|
+
def self.value_for(table, column, value)
|
5
|
+
klass = if table.associated_table(column).polymorphic_association? && ::Array === value && value.first.is_a?(Base)
|
6
|
+
PolymorphicArrayValue
|
7
|
+
else
|
8
|
+
AssociationQueryValue
|
9
|
+
end
|
10
|
+
|
11
|
+
klass.new(table.associated_table(column), value)
|
12
|
+
end
|
13
|
+
|
4
14
|
def initialize(predicate_builder)
|
5
15
|
@predicate_builder = predicate_builder
|
6
16
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class PredicateBuilder
|
3
|
+
class PolymorphicArrayHandler # :nodoc:
|
4
|
+
def initialize(predicate_builder)
|
5
|
+
@predicate_builder = predicate_builder
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(attribute, value)
|
9
|
+
table = value.associated_table
|
10
|
+
queries = value.type_to_ids_mapping.map do |type, ids|
|
11
|
+
{ table.association_foreign_type.to_s => type, table.association_foreign_key.to_s => ids }
|
12
|
+
end
|
13
|
+
|
14
|
+
predicates = queries.map { |query| predicate_builder.build_from_hash(query) }
|
15
|
+
|
16
|
+
if predicates.size > 1
|
17
|
+
type_and_ids_predicates = predicates.map { |type_predicate, id_predicate| Arel::Nodes::Grouping.new(type_predicate.and(id_predicate)) }
|
18
|
+
type_and_ids_predicates.inject(&:or)
|
19
|
+
else
|
20
|
+
predicates.first
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
attr_reader :predicate_builder
|
27
|
+
end
|
28
|
+
|
29
|
+
class PolymorphicArrayValue # :nodoc:
|
30
|
+
attr_reader :associated_table, :values
|
31
|
+
|
32
|
+
def initialize(associated_table, values)
|
33
|
+
@associated_table = associated_table
|
34
|
+
@values = values
|
35
|
+
end
|
36
|
+
|
37
|
+
def type_to_ids_mapping
|
38
|
+
default_hash = Hash.new { |hsh, key| hsh[key] = [] }
|
39
|
+
values.each_with_object(default_hash) { |value, hash| hash[base_class(value).name] << convert_to_id(value) }
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def primary_key(value)
|
45
|
+
associated_table.association_primary_key(base_class(value))
|
46
|
+
end
|
47
|
+
|
48
|
+
def base_class(value)
|
49
|
+
value.class.base_class
|
50
|
+
end
|
51
|
+
|
52
|
+
def convert_to_id(value)
|
53
|
+
value._read_attribute(primary_key(value))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|