activerecord 7.0.4.3 → 7.0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +318 -7
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/associations/collection_association.rb +1 -1
  5. data/lib/active_record/associations/collection_proxy.rb +5 -0
  6. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  7. data/lib/active_record/associations.rb +15 -6
  8. data/lib/active_record/attribute_methods/read.rb +1 -1
  9. data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
  10. data/lib/active_record/attribute_methods.rb +5 -7
  11. data/lib/active_record/callbacks.rb +12 -14
  12. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -16
  13. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +2 -1
  14. data/lib/active_record/connection_adapters/abstract_adapter.rb +4 -17
  15. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +15 -9
  16. data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
  17. data/lib/active_record/connection_adapters/mysql/quoting.rb +13 -2
  18. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  19. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  20. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -5
  21. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  22. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  23. data/lib/active_record/connection_adapters/postgresql/quoting.rb +5 -2
  24. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +3 -2
  25. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  26. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -1
  27. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -2
  28. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
  29. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -4
  31. data/lib/active_record/disable_joins_association_relation.rb +1 -1
  32. data/lib/active_record/explain_subscriber.rb +1 -1
  33. data/lib/active_record/gem_version.rb +2 -2
  34. data/lib/active_record/locking/optimistic.rb +32 -18
  35. data/lib/active_record/middleware/database_selector.rb +3 -3
  36. data/lib/active_record/migration/command_recorder.rb +1 -2
  37. data/lib/active_record/migration/compatibility.rb +19 -54
  38. data/lib/active_record/migration.rb +53 -4
  39. data/lib/active_record/persistence.rb +7 -5
  40. data/lib/active_record/railties/controller_runtime.rb +3 -4
  41. data/lib/active_record/reflection.rb +8 -0
  42. data/lib/active_record/relation/calculations.rb +50 -23
  43. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  44. data/lib/active_record/relation/query_attribute.rb +23 -0
  45. data/lib/active_record/relation/query_methods.rb +35 -8
  46. data/lib/active_record/result.rb +6 -4
  47. data/lib/active_record/schema_dumper.rb +4 -0
  48. data/lib/active_record/store.rb +1 -1
  49. data/lib/active_record/table_metadata.rb +6 -2
  50. data/lib/active_record/transactions.rb +3 -3
  51. data/lib/active_record/type/serialized.rb +8 -4
  52. data/lib/arel/filter_predications.rb +1 -1
  53. data/lib/arel/nodes/and.rb +4 -0
  54. data/lib/arel/nodes/filter.rb +1 -1
  55. metadata +13 -13
@@ -551,6 +551,41 @@ module ActiveRecord
551
551
 
552
552
  # This must be defined before the inherited hook, below
553
553
  class Current < Migration # :nodoc:
554
+ def create_table(table_name, **options)
555
+ if block_given?
556
+ super { |t| yield compatible_table_definition(t) }
557
+ else
558
+ super
559
+ end
560
+ end
561
+
562
+ def change_table(table_name, **options)
563
+ if block_given?
564
+ super { |t| yield compatible_table_definition(t) }
565
+ else
566
+ super
567
+ end
568
+ end
569
+
570
+ def create_join_table(table_1, table_2, **options)
571
+ if block_given?
572
+ super { |t| yield compatible_table_definition(t) }
573
+ else
574
+ super
575
+ end
576
+ end
577
+
578
+ def drop_table(table_name, **options)
579
+ if block_given?
580
+ super { |t| yield compatible_table_definition(t) }
581
+ else
582
+ super
583
+ end
584
+ end
585
+
586
+ def compatible_table_definition(t)
587
+ t
588
+ end
554
589
  end
555
590
 
556
591
  def self.inherited(subclass) # :nodoc:
@@ -916,9 +951,7 @@ module ActiveRecord
916
951
  end
917
952
 
918
953
  def method_missing(method, *arguments, &block)
919
- arg_list = arguments.map(&:inspect) * ", "
920
-
921
- say_with_time "#{method}(#{arg_list})" do
954
+ say_with_time "#{method}(#{format_arguments(arguments)})" do
922
955
  unless connection.respond_to? :revert
923
956
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
924
957
  arguments[0] = proper_table_name(arguments.first, table_name_options)
@@ -1026,6 +1059,22 @@ module ActiveRecord
1026
1059
  end
1027
1060
  end
1028
1061
 
1062
+ def format_arguments(arguments)
1063
+ arg_list = arguments[0...-1].map(&:inspect)
1064
+ last_arg = arguments.last
1065
+ if last_arg.is_a?(Hash)
1066
+ last_arg = last_arg.reject { |k, _v| internal_option?(k) }
1067
+ arg_list << last_arg.inspect unless last_arg.empty?
1068
+ else
1069
+ arg_list << last_arg.inspect
1070
+ end
1071
+ arg_list.join(", ")
1072
+ end
1073
+
1074
+ def internal_option?(option_name)
1075
+ option_name.start_with?("_")
1076
+ end
1077
+
1029
1078
  def command_recorder
1030
1079
  CommandRecorder.new(connection)
1031
1080
  end
@@ -1338,7 +1387,7 @@ module ActiveRecord
1338
1387
  # Stores the current environment in the database.
1339
1388
  def record_environment
1340
1389
  return if down?
1341
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1390
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.pool.db_config.env_name
1342
1391
  end
1343
1392
 
1344
1393
  def ran?(migration)
@@ -564,7 +564,7 @@ module ActiveRecord
564
564
  end
565
565
 
566
566
  # Returns true if this object was just created -- that is, prior to the last
567
- # save, the object didn't exist in the database and new_record? would have
567
+ # update or delete, the object didn't exist in the database and new_record? would have
568
568
  # returned true.
569
569
  def previously_new_record?
570
570
  @previously_new_record
@@ -663,6 +663,7 @@ module ActiveRecord
663
663
  def delete
664
664
  _delete_row if persisted?
665
665
  @destroyed = true
666
+ @previously_new_record = false
666
667
  freeze
667
668
  end
668
669
 
@@ -682,6 +683,7 @@ module ActiveRecord
682
683
  true
683
684
  end
684
685
  @destroyed = true
686
+ @previously_new_record = false
685
687
  freeze
686
688
  end
687
689
 
@@ -813,7 +815,7 @@ module ActiveRecord
813
815
  verify_readonly_attribute(name) || name
814
816
  end
815
817
 
816
- update_constraints = _primary_key_constraints_hash
818
+ update_constraints = _query_constraints_hash
817
819
  attributes = attributes.each_with_object({}) do |(k, v), h|
818
820
  h[k] = @attributes.write_cast_value(k, v)
819
821
  clear_attribute_change(k)
@@ -1028,7 +1030,7 @@ module ActiveRecord
1028
1030
  (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1029
1031
  end
1030
1032
 
1031
- def _primary_key_constraints_hash
1033
+ def _query_constraints_hash
1032
1034
  { @primary_key => id_in_database }
1033
1035
  end
1034
1036
 
@@ -1041,7 +1043,7 @@ module ActiveRecord
1041
1043
  end
1042
1044
 
1043
1045
  def _delete_row
1044
- self.class._delete_record(_primary_key_constraints_hash)
1046
+ self.class._delete_record(_query_constraints_hash)
1045
1047
  end
1046
1048
 
1047
1049
  def _touch_row(attribute_names, time)
@@ -1057,7 +1059,7 @@ module ActiveRecord
1057
1059
  def _update_row(attribute_names, attempted_action = "update")
1058
1060
  self.class._update_record(
1059
1061
  attributes_with_values(attribute_names),
1060
- _primary_key_constraints_hash
1062
+ _query_constraints_hash
1061
1063
  )
1062
1064
  end
1063
1065
 
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  end
29
29
 
30
30
  def cleanup_view_runtime
31
- if logger && logger.info? && ActiveRecord::Base.connected?
31
+ if logger && logger.info?
32
32
  db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
33
33
  self.db_runtime = (db_runtime || 0) + db_rt_before_render
34
34
  runtime = super
@@ -42,9 +42,8 @@ module ActiveRecord
42
42
 
43
43
  def append_info_to_payload(payload)
44
44
  super
45
- if ActiveRecord::Base.connected?
46
- payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
47
- end
45
+
46
+ payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
48
47
  end
49
48
  end
50
49
  end
@@ -485,6 +485,10 @@ module ActiveRecord
485
485
  foreign_key
486
486
  end
487
487
 
488
+ def join_primary_type
489
+ type
490
+ end
491
+
488
492
  def join_foreign_key
489
493
  active_record_primary_key
490
494
  end
@@ -588,6 +592,10 @@ module ActiveRecord
588
592
  options[:polymorphic]
589
593
  end
590
594
 
595
+ def polymorphic_name
596
+ active_record.polymorphic_name
597
+ end
598
+
591
599
  def add_as_source(seed)
592
600
  seed
593
601
  end
@@ -4,6 +4,47 @@ require "active_support/core_ext/enumerable"
4
4
 
5
5
  module ActiveRecord
6
6
  module Calculations
7
+ class ColumnAliasTracker # :nodoc:
8
+ def initialize(connection)
9
+ @connection = connection
10
+ @aliases = Hash.new(0)
11
+ end
12
+
13
+ def alias_for(field)
14
+ aliased_name = column_alias_for(field)
15
+
16
+ if @aliases[aliased_name] == 0
17
+ @aliases[aliased_name] = 1
18
+ aliased_name
19
+ else
20
+ # Update the count
21
+ count = @aliases[aliased_name] += 1
22
+ "#{truncate(aliased_name)}_#{count}"
23
+ end
24
+ end
25
+
26
+ private
27
+ # Converts the given field to the value that the database adapter returns as
28
+ # a usable column name:
29
+ #
30
+ # column_alias_for("users.id") # => "users_id"
31
+ # column_alias_for("sum(id)") # => "sum_id"
32
+ # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
33
+ # column_alias_for("count(*)") # => "count_all"
34
+ def column_alias_for(field)
35
+ column_alias = +field
36
+ column_alias.gsub!(/\*/, "all")
37
+ column_alias.gsub!(/\W+/, " ")
38
+ column_alias.strip!
39
+ column_alias.gsub!(/ +/, "_")
40
+ @connection.table_alias_for(column_alias)
41
+ end
42
+
43
+ def truncate(name)
44
+ name.slice(0, @connection.table_alias_length - 2)
45
+ end
46
+ end
47
+
7
48
  # Count the records.
8
49
  #
9
50
  # Person.count
@@ -86,7 +127,7 @@ module ActiveRecord
86
127
  def sum(identity_or_column = nil, &block)
87
128
  if block_given?
88
129
  values = map(&block)
89
- if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [])
130
+ if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [] || values.first.respond_to?(:coerce))
90
131
  identity_or_column = 0
91
132
  end
92
133
 
@@ -336,14 +377,16 @@ module ActiveRecord
336
377
  end
337
378
  group_fields = arel_columns(group_fields)
338
379
 
380
+ column_alias_tracker = ColumnAliasTracker.new(connection)
381
+
339
382
  group_aliases = group_fields.map { |field|
340
383
  field = connection.visitor.compile(field) if Arel.arel_node?(field)
341
- column_alias_for(field.to_s.downcase)
384
+ column_alias_tracker.alias_for(field.to_s.downcase)
342
385
  }
343
386
  group_columns = group_aliases.zip(group_fields)
344
387
 
345
388
  column = aggregate_column(column_name)
346
- column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
389
+ column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
347
390
  select_value = operation_over_aggregate_column(column, operation, distinct)
348
391
  select_value.as(connection.quote_column_name(column_alias))
349
392
 
@@ -372,9 +415,10 @@ module ActiveRecord
372
415
  end
373
416
 
374
417
  key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
375
- types[aliaz] = type_for(col_name) do
376
- calculated_data.column_types.fetch(aliaz, Type.default_value)
377
- end
418
+ types[aliaz] = col_name.try(:type_caster) ||
419
+ type_for(col_name) do
420
+ calculated_data.column_types.fetch(aliaz, Type.default_value)
421
+ end
378
422
  end
379
423
 
380
424
  hash_rows = calculated_data.cast_values(key_types).map! do |row|
@@ -398,23 +442,6 @@ module ActiveRecord
398
442
  end
399
443
  end
400
444
 
401
- # Converts the given field to the value that the database adapter returns as
402
- # a usable column name:
403
- #
404
- # column_alias_for("users.id") # => "users_id"
405
- # column_alias_for("sum(id)") # => "sum_id"
406
- # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
407
- # column_alias_for("count(*)") # => "count_all"
408
- def column_alias_for(field)
409
- column_alias = +field
410
- column_alias.gsub!(/\*/, "all")
411
- column_alias.gsub!(/\W+/, " ")
412
- column_alias.strip!
413
- column_alias.gsub!(/ +/, "_")
414
-
415
- connection.table_alias_for(column_alias)
416
- end
417
-
418
445
  def type_for(field, &block)
419
446
  field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
420
447
  @klass.type_for_attribute(field_name, &block)
@@ -18,7 +18,10 @@ module ActiveRecord
18
18
  def ids
19
19
  case value
20
20
  when Relation
21
- value.select_values.empty? ? value.select(primary_key) : value
21
+ relation = value
22
+ relation = relation.select(primary_key) if select_clause?
23
+ relation = relation.where(primary_type => polymorphic_name) if polymorphic_clause?
24
+ relation
22
25
  when Array
23
26
  value.map { |v| convert_to_id(v) }
24
27
  else
@@ -30,6 +33,22 @@ module ActiveRecord
30
33
  associated_table.join_primary_key
31
34
  end
32
35
 
36
+ def primary_type
37
+ associated_table.join_primary_type
38
+ end
39
+
40
+ def polymorphic_name
41
+ associated_table.polymorphic_name_association
42
+ end
43
+
44
+ def select_clause?
45
+ value.select_values.empty?
46
+ end
47
+
48
+ def polymorphic_clause?
49
+ primary_type && !value.where_values_hash.has_key?(primary_type)
50
+ end
51
+
33
52
  def convert_to_id(value)
34
53
  if value.respond_to?(primary_key)
35
54
  value.public_send(primary_key)
@@ -5,6 +5,20 @@ require "active_model/attribute"
5
5
  module ActiveRecord
6
6
  class Relation
7
7
  class QueryAttribute < ActiveModel::Attribute # :nodoc:
8
+ def initialize(...)
9
+ super
10
+
11
+ # The query attribute value may be mutated before we actually "compile" the query.
12
+ # To avoid that if the type uses a serializer we eagerly compute the value for database
13
+ if value_before_type_cast.is_a?(StatementCache::Substitute)
14
+ # we don't need to serialize StatementCache::Substitute
15
+ elsif @type.serialized?
16
+ value_for_database
17
+ elsif @type.mutable? # If the type is simply mutable, we deep_dup it.
18
+ @value_before_type_cast = @value_before_type_cast.deep_dup
19
+ end
20
+ end
21
+
8
22
  def type_cast(value)
9
23
  value
10
24
  end
@@ -35,6 +49,15 @@ module ActiveRecord
35
49
  @_unboundable
36
50
  end
37
51
 
52
+ def ==(other)
53
+ super && value_for_database == other.value_for_database
54
+ end
55
+ alias eql? ==
56
+
57
+ def hash
58
+ [self.class, name, value_for_database, type].hash
59
+ end
60
+
38
61
  private
39
62
  def infinity?(value)
40
63
  value.respond_to?(:infinite?) && value.infinite?
@@ -77,7 +77,11 @@ module ActiveRecord
77
77
  associations.each do |association|
78
78
  reflection = scope_association_reflection(association)
79
79
  @scope.joins!(association)
80
- self.not(reflection.table_name => { reflection.association_primary_key => nil })
80
+ if reflection.options[:class_name]
81
+ self.not(association => { reflection.association_primary_key => nil })
82
+ else
83
+ self.not(reflection.table_name => { reflection.association_primary_key => nil })
84
+ end
81
85
  end
82
86
 
83
87
  @scope
@@ -105,7 +109,11 @@ module ActiveRecord
105
109
  associations.each do |association|
106
110
  reflection = scope_association_reflection(association)
107
111
  @scope.left_outer_joins!(association)
108
- @scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
112
+ if reflection.options[:class_name]
113
+ @scope.where!(association => { reflection.association_primary_key => nil })
114
+ else
115
+ @scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
116
+ end
109
117
  end
110
118
 
111
119
  @scope
@@ -289,7 +297,7 @@ module ActiveRecord
289
297
  # You can also use one or more strings, which will be used unchanged as SELECT fields.
290
298
  #
291
299
  # Model.select('field AS field_one', 'other_field AS field_two')
292
- # # => [#<Model id: nil, field: "value", other_field: "value">]
300
+ # # => [#<Model id: nil, field_one: "value", field_two: "value">]
293
301
  #
294
302
  # If an alias was specified, it will be accessible from the resulting objects:
295
303
  #
@@ -436,13 +444,16 @@ module ActiveRecord
436
444
  self
437
445
  end
438
446
 
439
- # Allows to specify an order by a specific set of values. Depending on your
440
- # adapter this will either use a CASE statement or a built-in function.
447
+ # Allows to specify an order by a specific set of values.
441
448
  #
442
449
  # User.in_order_of(:id, [1, 5, 3])
443
450
  # # SELECT "users".* FROM "users"
444
- # # ORDER BY FIELD("users"."id", 1, 5, 3)
445
451
  # # WHERE "users"."id" IN (1, 5, 3)
452
+ # # ORDER BY CASE
453
+ # # WHEN "users"."id" = 1 THEN 1
454
+ # # WHEN "users"."id" = 5 THEN 2
455
+ # # WHEN "users"."id" = 3 THEN 3
456
+ # # END ASC
446
457
  #
447
458
  def in_order_of(column, values)
448
459
  klass.disallow_raw_sql!([column], permit: connection.column_name_with_order_matcher)
@@ -454,9 +465,16 @@ module ActiveRecord
454
465
  values = values.map { |value| type_caster.type_cast_for_database(column, value) }
455
466
  arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column
456
467
 
468
+ where_clause =
469
+ if values.include?(nil)
470
+ arel_column.in(values.compact).or(arel_column.eq(nil))
471
+ else
472
+ arel_column.in(values)
473
+ end
474
+
457
475
  spawn
458
- .order!(connection.field_ordered_value(arel_column, values))
459
- .where!(arel_column.in(values))
476
+ .order!(build_case_for_value_position(arel_column, values))
477
+ .where!(where_clause)
460
478
  end
461
479
 
462
480
  # Replaces any existing order defined on the relation with the specified order.
@@ -1661,6 +1679,15 @@ module ActiveRecord
1661
1679
  end
1662
1680
  end
1663
1681
 
1682
+ def build_case_for_value_position(column, values)
1683
+ node = Arel::Nodes::Case.new
1684
+ values.each.with_index(1) do |value, order|
1685
+ node.when(column.eq(value)).then(order)
1686
+ end
1687
+
1688
+ Arel::Nodes::Ascending.new(node)
1689
+ end
1690
+
1664
1691
  def resolve_arel_attributes(attrs)
1665
1692
  attrs.flat_map do |attr|
1666
1693
  case attr
@@ -108,7 +108,7 @@ module ActiveRecord
108
108
  type = if type_overrides.is_a?(Array)
109
109
  type_overrides.first
110
110
  else
111
- column_type(columns.first, type_overrides)
111
+ column_type(columns.first, 0, type_overrides)
112
112
  end
113
113
 
114
114
  rows.map do |(value)|
@@ -118,7 +118,7 @@ module ActiveRecord
118
118
  types = if type_overrides.is_a?(Array)
119
119
  type_overrides
120
120
  else
121
- columns.map { |name| column_type(name, type_overrides) }
121
+ columns.map.with_index { |name, i| column_type(name, i, type_overrides) }
122
122
  end
123
123
 
124
124
  rows.map do |values|
@@ -135,9 +135,11 @@ module ActiveRecord
135
135
  end
136
136
 
137
137
  private
138
- def column_type(name, type_overrides = {})
138
+ def column_type(name, index, type_overrides)
139
139
  type_overrides.fetch(name) do
140
- column_types.fetch(name, Type.default_value)
140
+ column_types.fetch(index) do
141
+ column_types.fetch(name, Type.default_value)
142
+ end
141
143
  end
142
144
  end
143
145
 
@@ -292,6 +292,10 @@ module ActiveRecord
292
292
  end
293
293
 
294
294
  def remove_prefix_and_suffix(table)
295
+ # This method appears at the top when profiling active_record test cases run.
296
+ # Avoid costly calculation when there are no prefix and suffix.
297
+ return table if @options[:table_name_prefix].blank? && @options[:table_name_suffix].blank?
298
+
295
299
  prefix = Regexp.escape(@options[:table_name_prefix].to_s)
296
300
  suffix = Regexp.escape(@options[:table_name_suffix].to_s)
297
301
  table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
@@ -70,7 +70,7 @@ module ActiveRecord
70
70
  #
71
71
  # The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
72
72
  #
73
- # User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
73
+ # User.stored_attributes[:settings] # => [:color, :homepage, :two_factor_auth, :login_retry]
74
74
  #
75
75
  # == Overwriting default accessors
76
76
  #
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class TableMetadata # :nodoc:
5
- delegate :join_primary_key, :join_foreign_key, :join_foreign_type, to: :reflection
5
+ delegate :join_primary_key, :join_primary_type, :join_foreign_key, :join_foreign_type, to: :reflection
6
6
 
7
7
  def initialize(klass, arel_table, reflection = nil)
8
8
  @klass = klass
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  end
20
20
 
21
21
  def has_column?(column_name)
22
- klass&.columns_hash.key?(column_name)
22
+ klass&.columns_hash&.key?(column_name)
23
23
  end
24
24
 
25
25
  def associated_with?(table_name)
@@ -54,6 +54,10 @@ module ActiveRecord
54
54
  reflection&.polymorphic?
55
55
  end
56
56
 
57
+ def polymorphic_name_association
58
+ reflection&.polymorphic_name
59
+ end
60
+
57
61
  def through_association?
58
62
  reflection&.through_reflection?
59
63
  end
@@ -336,9 +336,9 @@ module ActiveRecord
336
336
  @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
337
337
  end
338
338
 
339
- # Executes +method+ within a transaction and captures its return value as a
340
- # status flag. If the status is true the transaction is committed, otherwise
341
- # a ROLLBACK is issued. In any case the status flag is returned.
339
+ # Executes a block within a transaction and captures its return value as a
340
+ # status flag. If the status is true, the transaction is committed,
341
+ # otherwise a ROLLBACK is issued. In any case, the status flag is returned.
342
342
  #
343
343
  # This method is available within the context of an ActiveRecord::Base
344
344
  # instance.
@@ -55,6 +55,10 @@ module ActiveRecord
55
55
  coder.respond_to?(:object_class) && value.is_a?(coder.object_class)
56
56
  end
57
57
 
58
+ def serialized? # :nodoc:
59
+ true
60
+ end
61
+
58
62
  private
59
63
  def default_value?(value)
60
64
  value == coder.load(nil)
@@ -63,11 +67,11 @@ module ActiveRecord
63
67
  def encoded(value)
64
68
  return if default_value?(value)
65
69
  payload = coder.dump(value)
66
- if payload && binary? && payload.encoding != Encoding::BINARY
67
- payload = payload.dup if payload.frozen?
68
- payload.force_encoding(Encoding::BINARY)
70
+ if payload && @subtype.binary?
71
+ ActiveModel::Type::Binary::Data.new(payload)
72
+ else
73
+ payload
69
74
  end
70
- payload
71
75
  end
72
76
  end
73
77
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Arel
3
+ module Arel # :nodoc: all
4
4
  module FilterPredications
5
5
  def filter(expr)
6
6
  Nodes::Filter.new(self, expr)
@@ -18,6 +18,10 @@ module Arel # :nodoc: all
18
18
  children[1]
19
19
  end
20
20
 
21
+ def fetch_attribute(&block)
22
+ children.any? && children.all? { |child| child.fetch_attribute(&block) }
23
+ end
24
+
21
25
  def hash
22
26
  children.hash
23
27
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Arel
3
+ module Arel # :nodoc: all
4
4
  module Nodes
5
5
  class Filter < Binary
6
6
  include Arel::WindowPredications