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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +159 -7
- data/README.rdoc +2 -2
- data/lib/active_record/associations/has_one_association.rb +4 -0
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +7 -5
- data/lib/active_record/associations.rb +15 -6
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
- data/lib/active_record/attribute_methods.rb +5 -7
- data/lib/active_record/autosave_association.rb +9 -5
- data/lib/active_record/callbacks.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -16
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +2 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +4 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +7 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -5
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/locking/optimistic.rb +32 -18
- data/lib/active_record/middleware/database_selector.rb +3 -3
- data/lib/active_record/migration/command_recorder.rb +1 -2
- data/lib/active_record/migration/compatibility.rb +7 -0
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/persistence.rb +4 -4
- data/lib/active_record/reflection.rb +8 -0
- data/lib/active_record/relation/calculations.rb +50 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +11 -3
- data/lib/active_record/result.rb +6 -4
- data/lib/active_record/schema_dumper.rb +4 -0
- data/lib/active_record/store.rb +1 -1
- data/lib/active_record/table_metadata.rb +5 -1
- data/lib/active_record/type/serialized.rb +4 -4
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/filter.rb +1 -1
- 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 =
|
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(
|
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,
|
@@ -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] ||
|
@@ -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
|
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
|
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 =
|
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
|
-
|
122
|
-
|
123
|
-
locking_column = self.class.locking_column
|
125
|
+
affected_rows = super
|
124
126
|
|
125
|
-
|
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
|
-
|
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
|
47
|
-
#
|
48
|
-
#
|
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
|
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
|
@@ -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.
|
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 =
|
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
|
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(
|
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
|
-
|
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
|
-
|
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 =
|
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] =
|
376
|
-
|
377
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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,
|
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
|
#
|
data/lib/active_record/result.rb
CHANGED
@@ -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(
|
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")
|
data/lib/active_record/store.rb
CHANGED
@@ -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?
|
67
|
-
|
68
|
-
|
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
|