activerecord 7.0.4.3 → 7.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +159 -7
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/associations/has_one_association.rb +4 -0
  5. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  6. data/lib/active_record/associations/singular_association.rb +7 -5
  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/autosave_association.rb +9 -5
  12. data/lib/active_record/callbacks.rb +12 -14
  13. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -16
  14. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +2 -1
  15. data/lib/active_record/connection_adapters/abstract_adapter.rb +4 -0
  16. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +7 -3
  17. data/lib/active_record/connection_adapters/mysql/quoting.rb +8 -0
  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/schema_statements.rb +3 -2
  24. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  25. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -1
  26. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  27. data/lib/active_record/disable_joins_association_relation.rb +1 -1
  28. data/lib/active_record/explain_subscriber.rb +1 -1
  29. data/lib/active_record/gem_version.rb +2 -2
  30. data/lib/active_record/locking/optimistic.rb +32 -18
  31. data/lib/active_record/middleware/database_selector.rb +3 -3
  32. data/lib/active_record/migration/command_recorder.rb +1 -2
  33. data/lib/active_record/migration/compatibility.rb +7 -0
  34. data/lib/active_record/migration.rb +1 -1
  35. data/lib/active_record/persistence.rb +4 -4
  36. data/lib/active_record/reflection.rb +8 -0
  37. data/lib/active_record/relation/calculations.rb +50 -23
  38. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  39. data/lib/active_record/relation/predicate_builder.rb +2 -1
  40. data/lib/active_record/relation/query_methods.rb +11 -3
  41. data/lib/active_record/result.rb +6 -4
  42. data/lib/active_record/schema_dumper.rb +4 -0
  43. data/lib/active_record/store.rb +1 -1
  44. data/lib/active_record/table_metadata.rb +5 -1
  45. data/lib/active_record/type/serialized.rb +4 -4
  46. data/lib/arel/filter_predications.rb +1 -1
  47. data/lib/arel/nodes/filter.rb +1 -1
  48. metadata +13 -13
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  attr_reader :schema, :identifier
13
13
 
14
14
  def initialize(schema, identifier)
15
- @schema, @identifier = unquote(schema), unquote(identifier)
15
+ @schema, @identifier = Utils.unquote_identifier(schema), Utils.unquote_identifier(identifier)
16
16
  end
17
17
 
18
18
  def to_s
@@ -40,15 +40,6 @@ module ActiveRecord
40
40
  def parts
41
41
  @parts ||= [@schema, @identifier].compact
42
42
  end
43
-
44
- private
45
- def unquote(part)
46
- if part && part.start_with?('"')
47
- part[1..-2]
48
- else
49
- part
50
- end
51
- end
52
43
  end
53
44
 
54
45
  module Utils # :nodoc:
@@ -74,6 +65,14 @@ module ActiveRecord
74
65
  end
75
66
  PostgreSQL::Name.new(schema, table)
76
67
  end
68
+
69
+ def unquote_identifier(identifier)
70
+ if identifier && identifier.start_with?('"')
71
+ identifier[1..-2]
72
+ else
73
+ identifier
74
+ end
75
+ end
77
76
  end
78
77
  end
79
78
  end
@@ -977,7 +977,7 @@ module ActiveRecord
977
977
  PG::TextDecoder::TimestampUtc :
978
978
  PG::TextDecoder::TimestampWithoutTimeZone
979
979
 
980
- @timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
980
+ @timestamp_decoder = decoder_class.new(**@timestamp_decoder.to_h)
981
981
  @connection.type_map_for_results.add_coder(@timestamp_decoder)
982
982
 
983
983
  @default_timezone = ActiveRecord.default_timezone
@@ -480,6 +480,7 @@ module ActiveRecord
480
480
  if column.has_default?
481
481
  type = lookup_cast_type_from_column(column)
482
482
  default = type.deserialize(column.default)
483
+ default = -> { column.default_function } if default.nil?
483
484
  end
484
485
 
485
486
  @definition.column(column_name, column.type,
@@ -30,7 +30,7 @@ module ActiveRecord
30
30
  record[key]
31
31
  end
32
32
 
33
- records = ids.flat_map { |id| records_by_id[id.to_i] }
33
+ records = ids.flat_map { |id| records_by_id[id] }
34
34
  records.compact!
35
35
 
36
36
  @records = records
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # On the other hand, we want to monitor the performance of our real database
22
22
  # queries, not the performance of the access to the query cache.
23
23
  IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
24
- EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
24
+ EXPLAINED_SQLS = /\A\s*(\/\*.*\*\/)?\s*(with|select|update|delete|insert)\b/i
25
25
  def ignore_payload?(payload)
26
26
  payload[:exception] ||
27
27
  payload[:cached] ||
@@ -9,8 +9,8 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 4
13
- PRE = "3"
12
+ TINY = 6
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Locking
5
- # == What is Optimistic Locking
5
+ # == What is \Optimistic \Locking
6
6
  #
7
7
  # Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of
8
8
  # conflicts with the data. It does this by checking whether another process has made changes to a record since
9
- # it was opened, an <tt>ActiveRecord::StaleObjectError</tt> exception is thrown if that has occurred
9
+ # it was opened, an ActiveRecord::StaleObjectError exception is thrown if that has occurred
10
10
  # and the update is ignored.
11
11
  #
12
- # Check out <tt>ActiveRecord::Locking::Pessimistic</tt> for an alternative.
12
+ # Check out +ActiveRecord::Locking::Pessimistic+ for an alternative.
13
13
  #
14
14
  # == Usage
15
15
  #
@@ -69,6 +69,11 @@ module ActiveRecord
69
69
  end
70
70
  end
71
71
 
72
+ def initialize_dup(other) # :nodoc:
73
+ super
74
+ _clear_locking_column if locking_enabled?
75
+ end
76
+
72
77
  private
73
78
  def _create_record(attribute_names = self.attribute_names)
74
79
  if locking_enabled?
@@ -91,8 +96,7 @@ module ActiveRecord
91
96
  locking_column = self.class.locking_column
92
97
  lock_attribute_was = @attributes[locking_column]
93
98
 
94
- update_constraints = _primary_key_constraints_hash
95
- update_constraints[locking_column] = _lock_value_for_database(locking_column)
99
+ update_constraints = _query_constraints_hash
96
100
 
97
101
  attribute_names = attribute_names.dup if attribute_names.frozen?
98
102
  attribute_names << locking_column
@@ -118,16 +122,9 @@ module ActiveRecord
118
122
  end
119
123
 
120
124
  def destroy_row
121
- return super unless locking_enabled?
122
-
123
- locking_column = self.class.locking_column
125
+ affected_rows = super
124
126
 
125
- delete_constraints = _primary_key_constraints_hash
126
- delete_constraints[locking_column] = _lock_value_for_database(locking_column)
127
-
128
- affected_rows = self.class._delete_record(delete_constraints)
129
-
130
- if affected_rows != 1
127
+ if locking_enabled? && affected_rows != 1
131
128
  raise ActiveRecord::StaleObjectError.new(self, "destroy")
132
129
  end
133
130
 
@@ -142,6 +139,18 @@ module ActiveRecord
142
139
  end
143
140
  end
144
141
 
142
+ def _clear_locking_column
143
+ self[self.class.locking_column] = nil
144
+ clear_attribute_change(self.class.locking_column)
145
+ end
146
+
147
+ def _query_constraints_hash
148
+ return super unless locking_enabled?
149
+
150
+ locking_column = self.class.locking_column
151
+ super.merge(locking_column => _lock_value_for_database(locking_column))
152
+ end
153
+
145
154
  module ClassMethods
146
155
  DEFAULT_LOCKING_COLUMN = "lock_version"
147
156
 
@@ -159,10 +168,7 @@ module ActiveRecord
159
168
  end
160
169
 
161
170
  # The version column used for optimistic locking. Defaults to +lock_version+.
162
- def locking_column
163
- @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
164
- @locking_column
165
- end
171
+ attr_reader :locking_column
166
172
 
167
173
  # Reset the column used for optimistic locking back to the +lock_version+ default.
168
174
  def reset_locking_column
@@ -182,6 +188,14 @@ module ActiveRecord
182
188
  end
183
189
  super
184
190
  end
191
+
192
+ private
193
+ def inherited(base)
194
+ super
195
+ base.class_eval do
196
+ @locking_column = DEFAULT_LOCKING_COLUMN
197
+ end
198
+ end
185
199
  end
186
200
  end
187
201
 
@@ -43,9 +43,9 @@ module ActiveRecord
43
43
  # config.active_record.database_resolver = MyResolver
44
44
  # config.active_record.database_resolver_context = MyResolver::MySession
45
45
  #
46
- # Note: If you are using `rails new my_app --minimal` you will need to call
47
- # `require "active_support/core_ext/integer/time"` to load the libraries
48
- # for +Time+.
46
+ # Note: If you are using <tt>rails new my_app --minimal</tt> you will need
47
+ # to call <tt>require "active_support/core_ext/integer/time"</tt> to load
48
+ # the core extension in order to use +2.seconds+
49
49
  class DatabaseSelector
50
50
  def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
51
51
  @app = app
@@ -12,7 +12,6 @@ module ActiveRecord
12
12
  # * add_index
13
13
  # * add_reference
14
14
  # * add_timestamps
15
- # * change_column
16
15
  # * change_column_default (must supply a +:from+ and +:to+ option)
17
16
  # * change_column_null
18
17
  # * change_column_comment (must supply a +:from+ and +:to+ option)
@@ -24,7 +23,7 @@ module ActiveRecord
24
23
  # * drop_table (must supply a block)
25
24
  # * enable_extension
26
25
  # * remove_column (must supply a type)
27
- # * remove_columns (must specify at least one column name or more)
26
+ # * remove_columns (must supply a +:type+ option)
28
27
  # * remove_foreign_key (must supply a second table)
29
28
  # * remove_check_constraint
30
29
  # * remove_index
@@ -159,6 +159,13 @@ module ActiveRecord
159
159
  options[:precision] ||= nil
160
160
  super
161
161
  end
162
+
163
+ private
164
+ def raise_on_if_exist_options(options)
165
+ end
166
+
167
+ def raise_on_duplicate_column(name)
168
+ end
162
169
  end
163
170
 
164
171
  module CommandRecorder
@@ -1338,7 +1338,7 @@ module ActiveRecord
1338
1338
  # Stores the current environment in the database.
1339
1339
  def record_environment
1340
1340
  return if down?
1341
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1341
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.pool.db_config.env_name
1342
1342
  end
1343
1343
 
1344
1344
  def ran?(migration)
@@ -813,7 +813,7 @@ module ActiveRecord
813
813
  verify_readonly_attribute(name) || name
814
814
  end
815
815
 
816
- update_constraints = _primary_key_constraints_hash
816
+ update_constraints = _query_constraints_hash
817
817
  attributes = attributes.each_with_object({}) do |(k, v), h|
818
818
  h[k] = @attributes.write_cast_value(k, v)
819
819
  clear_attribute_change(k)
@@ -1028,7 +1028,7 @@ module ActiveRecord
1028
1028
  (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1029
1029
  end
1030
1030
 
1031
- def _primary_key_constraints_hash
1031
+ def _query_constraints_hash
1032
1032
  { @primary_key => id_in_database }
1033
1033
  end
1034
1034
 
@@ -1041,7 +1041,7 @@ module ActiveRecord
1041
1041
  end
1042
1042
 
1043
1043
  def _delete_row
1044
- self.class._delete_record(_primary_key_constraints_hash)
1044
+ self.class._delete_record(_query_constraints_hash)
1045
1045
  end
1046
1046
 
1047
1047
  def _touch_row(attribute_names, time)
@@ -1057,7 +1057,7 @@ module ActiveRecord
1057
1057
  def _update_row(attribute_names, attempted_action = "update")
1058
1058
  self.class._update_record(
1059
1059
  attributes_with_values(attribute_names),
1060
- _primary_key_constraints_hash
1060
+ _query_constraints_hash
1061
1061
  )
1062
1062
  end
1063
1063
 
@@ -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)
@@ -65,7 +65,8 @@ module ActiveRecord
65
65
  end
66
66
 
67
67
  def build_bind_attribute(column_name, value)
68
- Relation::QueryAttribute.new(column_name, value, table.type(column_name))
68
+ type = table.type(column_name)
69
+ Relation::QueryAttribute.new(column_name, type.immutable_value(value), type)
69
70
  end
70
71
 
71
72
  def resolve_arel_attribute(table_name, column_name, &block)
@@ -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 @scope.table_name == reflection.table_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 @scope.table_name == reflection.table_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
  #
@@ -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
@@ -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
@@ -63,11 +63,11 @@ module ActiveRecord
63
63
  def encoded(value)
64
64
  return if default_value?(value)
65
65
  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)
66
+ if payload && @subtype.binary?
67
+ ActiveModel::Type::Binary::Data.new(payload)
68
+ else
69
+ payload
69
70
  end
70
- payload
71
71
  end
72
72
  end
73
73
  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)
@@ -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