activerecord 6.0.0.rc1 → 6.0.3.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +251 -3
- data/README.rdoc +1 -1
- data/lib/active_record.rb +1 -0
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +0 -1
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +5 -1
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -3
- data/lib/active_record/associations/collection_association.rb +6 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -3
- data/lib/active_record/associations/has_many_association.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +23 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
- data/lib/active_record/associations/preloader.rb +2 -3
- data/lib/active_record/associations/preloader/association.rb +3 -1
- data/lib/active_record/attribute_assignment.rb +0 -1
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods.rb +0 -51
- data/lib/active_record/attribute_methods/before_type_cast.rb +0 -1
- data/lib/active_record/attribute_methods/dirty.rb +8 -3
- data/lib/active_record/attribute_methods/primary_key.rb +0 -2
- data/lib/active_record/attribute_methods/read.rb +0 -1
- data/lib/active_record/attribute_methods/serialization.rb +0 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -2
- data/lib/active_record/attribute_methods/write.rb +0 -1
- data/lib/active_record/attributes.rb +0 -1
- data/lib/active_record/autosave_association.rb +11 -7
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/yaml_column.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +107 -13
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +21 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +27 -27
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -37
- data/lib/active_record/connection_adapters/abstract/transaction.rb +14 -7
- data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -25
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +25 -32
- data/lib/active_record/connection_adapters/connection_specification.rb +3 -4
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -12
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +3 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +8 -8
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +9 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -29
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +17 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +8 -7
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +23 -8
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +17 -22
- data/lib/active_record/core.rb +8 -6
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations.rb +60 -31
- data/lib/active_record/database_configurations/url_config.rb +0 -1
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +9 -0
- data/lib/active_record/explain.rb +0 -1
- data/lib/active_record/fixture_set/table_row.rb +0 -1
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +11 -9
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +0 -3
- data/lib/active_record/insert_all.rb +5 -6
- data/lib/active_record/internal_metadata.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +0 -1
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +3 -4
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -8
- data/lib/active_record/migration.rb +43 -32
- data/lib/active_record/migration/command_recorder.rb +6 -18
- data/lib/active_record/migration/compatibility.rb +3 -3
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +3 -2
- data/lib/active_record/nested_attributes.rb +0 -2
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +4 -5
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +1 -2
- data/lib/active_record/railties/collection_cache_association_loading.rb +1 -1
- data/lib/active_record/railties/databases.rake +63 -23
- data/lib/active_record/reflection.rb +9 -9
- data/lib/active_record/relation.rb +13 -1
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +3 -5
- data/lib/active_record/relation/delegation.rb +7 -6
- data/lib/active_record/relation/finder_methods.rb +14 -4
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +6 -3
- data/lib/active_record/relation/predicate_builder.rb +1 -5
- data/lib/active_record/relation/query_methods.rb +94 -55
- data/lib/active_record/relation/spawn_methods.rb +0 -1
- data/lib/active_record/relation/where_clause.rb +0 -1
- data/lib/active_record/result.rb +0 -1
- data/lib/active_record/sanitization.rb +30 -2
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +5 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +3 -3
- data/lib/active_record/store.rb +1 -1
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +21 -10
- data/lib/active_record/tasks/database_tasks.rb +76 -8
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +0 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +0 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +2 -1
- data/lib/active_record/timestamp.rb +26 -17
- data/lib/active_record/touch_later.rb +3 -2
- data/lib/active_record/transactions.rb +18 -19
- data/lib/active_record/type.rb +0 -1
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/arel.rb +17 -6
- data/lib/arel/predications.rb +5 -6
- data/lib/arel/visitors/depth_first.rb +1 -2
- data/lib/arel/visitors/dot.rb +0 -1
- data/lib/arel/visitors/mssql.rb +0 -1
- data/lib/arel/visitors/oracle.rb +1 -2
- data/lib/arel/visitors/oracle12.rb +0 -1
- data/lib/arel/visitors/postgresql.rb +0 -1
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +23 -27
- data/lib/arel/visitors/visitor.rb +9 -6
- data/lib/arel/visitors/where_sql.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +0 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +0 -1
- metadata +13 -9
@@ -378,7 +378,9 @@ module ActiveRecord
|
|
378
378
|
end
|
379
379
|
|
380
380
|
def remove_records(existing_records, records, method)
|
381
|
-
|
381
|
+
catch(:abort) do
|
382
|
+
records.each { |record| callback(:before_remove, record) }
|
383
|
+
end || return
|
382
384
|
|
383
385
|
delete_records(existing_records, method) if existing_records.any?
|
384
386
|
@target -= records
|
@@ -434,7 +436,9 @@ module ActiveRecord
|
|
434
436
|
end
|
435
437
|
|
436
438
|
def replace_on_target(record, index, skip_callbacks)
|
437
|
-
|
439
|
+
catch(:abort) do
|
440
|
+
callback(:before_add, record)
|
441
|
+
end || return unless skip_callbacks
|
438
442
|
|
439
443
|
set_inverse_instance(record)
|
440
444
|
|
@@ -27,7 +27,7 @@ module ActiveRecord
|
|
27
27
|
# is computed directly through SQL and does not trigger by itself the
|
28
28
|
# instantiation of the actual post records.
|
29
29
|
class CollectionProxy < Relation
|
30
|
-
def initialize(klass, association) #:nodoc:
|
30
|
+
def initialize(klass, association, **) #:nodoc:
|
31
31
|
@association = association
|
32
32
|
super klass
|
33
33
|
|
@@ -1029,7 +1029,7 @@ module ActiveRecord
|
|
1029
1029
|
alias_method :append, :<<
|
1030
1030
|
alias_method :concat, :<<
|
1031
1031
|
|
1032
|
-
def prepend(*args)
|
1032
|
+
def prepend(*args) # :nodoc:
|
1033
1033
|
raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
|
1034
1034
|
end
|
1035
1035
|
|
@@ -1101,7 +1101,6 @@ module ActiveRecord
|
|
1101
1101
|
delegate(*delegate_methods, to: :scope)
|
1102
1102
|
|
1103
1103
|
private
|
1104
|
-
|
1105
1104
|
def find_nth_with_limit(index, limit)
|
1106
1105
|
load_target if find_from_target?
|
1107
1106
|
super
|
@@ -64,16 +64,21 @@ module ActiveRecord
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def initialize(base, table, associations)
|
67
|
+
def initialize(base, table, associations, join_type)
|
68
68
|
tree = self.class.make_tree associations
|
69
69
|
@join_root = JoinBase.new(base, table, build(tree, base))
|
70
|
+
@join_type = join_type
|
71
|
+
end
|
72
|
+
|
73
|
+
def base_klass
|
74
|
+
join_root.base_klass
|
70
75
|
end
|
71
76
|
|
72
77
|
def reflections
|
73
78
|
join_root.drop(1).map!(&:reflection)
|
74
79
|
end
|
75
80
|
|
76
|
-
def join_constraints(joins_to_add,
|
81
|
+
def join_constraints(joins_to_add, alias_tracker)
|
77
82
|
@alias_tracker = alias_tracker
|
78
83
|
|
79
84
|
construct_tables!(join_root)
|
@@ -82,9 +87,9 @@ module ActiveRecord
|
|
82
87
|
joins.concat joins_to_add.flat_map { |oj|
|
83
88
|
construct_tables!(oj.join_root)
|
84
89
|
if join_root.match? oj.join_root
|
85
|
-
walk join_root, oj.
|
90
|
+
walk(join_root, oj.join_root, oj.join_type)
|
86
91
|
else
|
87
|
-
make_join_constraints(oj.join_root, join_type)
|
92
|
+
make_join_constraints(oj.join_root, oj.join_type)
|
88
93
|
end
|
89
94
|
}
|
90
95
|
end
|
@@ -100,7 +105,9 @@ module ActiveRecord
|
|
100
105
|
|
101
106
|
model_cache = Hash.new { |h, klass| h[klass] = {} }
|
102
107
|
parents = model_cache[join_root]
|
108
|
+
|
103
109
|
column_aliases = aliases.column_aliases join_root
|
110
|
+
column_aliases += explicit_selections(column_aliases, result_set)
|
104
111
|
|
105
112
|
message_bus = ActiveSupport::Notifications.instrumenter
|
106
113
|
|
@@ -125,11 +132,18 @@ module ActiveRecord
|
|
125
132
|
end
|
126
133
|
|
127
134
|
protected
|
128
|
-
attr_reader :join_root
|
135
|
+
attr_reader :join_root, :join_type
|
129
136
|
|
130
137
|
private
|
131
138
|
attr_reader :alias_tracker
|
132
139
|
|
140
|
+
def explicit_selections(root_column_aliases, result_set)
|
141
|
+
root_names = root_column_aliases.map(&:name).to_set
|
142
|
+
result_set.columns
|
143
|
+
.reject { |n| root_names.include?(n) || n =~ /\At\d+_r\d+\z/ }
|
144
|
+
.map { |n| Aliases::Column.new(n, n) }
|
145
|
+
end
|
146
|
+
|
133
147
|
def aliases
|
134
148
|
@aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
|
135
149
|
columns = join_part.column_names.each_with_index.map { |column_name, j|
|
@@ -151,7 +165,7 @@ module ActiveRecord
|
|
151
165
|
end
|
152
166
|
end
|
153
167
|
|
154
|
-
def make_constraints(parent, child, join_type
|
168
|
+
def make_constraints(parent, child, join_type)
|
155
169
|
foreign_table = parent.table
|
156
170
|
foreign_klass = parent.base_klass
|
157
171
|
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
@@ -173,13 +187,13 @@ module ActiveRecord
|
|
173
187
|
join ? "#{name}_join" : name
|
174
188
|
end
|
175
189
|
|
176
|
-
def walk(left, right)
|
190
|
+
def walk(left, right, join_type)
|
177
191
|
intersection, missing = right.children.map { |node1|
|
178
192
|
[left.children.find { |node2| node1.match? node2 }, node1]
|
179
193
|
}.partition(&:first)
|
180
194
|
|
181
|
-
joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r) }
|
182
|
-
joins.concat missing.flat_map { |_, n| make_constraints(left, n) }
|
195
|
+
joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r, join_type) }
|
196
|
+
joins.concat missing.flat_map { |_, n| make_constraints(left, n, join_type) }
|
183
197
|
end
|
184
198
|
|
185
199
|
def find_reflection(klass, name)
|
@@ -37,15 +37,14 @@ module ActiveRecord
|
|
37
37
|
nodes = arel.constraints.first
|
38
38
|
|
39
39
|
others = nodes.children.extract! do |node|
|
40
|
-
Arel.fetch_attribute(node) { |attr| attr.relation.name
|
40
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
41
41
|
end
|
42
42
|
|
43
43
|
joins << table.create_join(table, table.create_on(nodes), join_type)
|
44
44
|
|
45
45
|
unless others.empty?
|
46
46
|
joins.concat arel.join_sources
|
47
|
-
|
48
|
-
right.expr.children.concat(others)
|
47
|
+
append_constraints(joins.last, others)
|
49
48
|
end
|
50
49
|
|
51
50
|
# The current table in this iteration becomes the foreign table in the next
|
@@ -65,6 +64,16 @@ module ActiveRecord
|
|
65
64
|
|
66
65
|
@readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value
|
67
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def append_constraints(join, constraints)
|
70
|
+
if join.is_a?(Arel::Nodes::StringJoin)
|
71
|
+
join_string = table.create_and(constraints.unshift(join.left))
|
72
|
+
join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
|
73
|
+
else
|
74
|
+
join.right.expr.children.concat(constraints)
|
75
|
+
end
|
76
|
+
end
|
68
77
|
end
|
69
78
|
end
|
70
79
|
end
|
@@ -95,7 +95,6 @@ module ActiveRecord
|
|
95
95
|
end
|
96
96
|
|
97
97
|
private
|
98
|
-
|
99
98
|
# Loads all the given data into +records+ for the +association+.
|
100
99
|
def preloaders_on(association, records, scope, polymorphic_parent = false)
|
101
100
|
case association
|
@@ -112,7 +111,7 @@ module ActiveRecord
|
|
112
111
|
association.flat_map { |parent, child|
|
113
112
|
grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
|
114
113
|
loaders = preloaders_for_reflection(reflection, reflection_records, scope)
|
115
|
-
recs = loaders.flat_map(&:preloaded_records)
|
114
|
+
recs = loaders.flat_map(&:preloaded_records).uniq
|
116
115
|
child_polymorphic_parent = reflection && reflection.options[:polymorphic]
|
117
116
|
loaders.concat Array.wrap(child).flat_map { |assoc|
|
118
117
|
preloaders_on assoc, recs, scope, child_polymorphic_parent
|
@@ -185,7 +184,7 @@ module ActiveRecord
|
|
185
184
|
# and attach it to a relation. The class returned implements a `run` method
|
186
185
|
# that accepts a preloader.
|
187
186
|
def preloader_for(reflection, owners)
|
188
|
-
if owners.
|
187
|
+
if owners.all? { |o| o.association(reflection.name).loaded? }
|
189
188
|
return AlreadyLoaded
|
190
189
|
end
|
191
190
|
reflection.check_preloadable!
|
@@ -27,7 +27,9 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def records_by_owner
|
30
|
-
|
30
|
+
# owners can be duplicated when a relation has a collection association join
|
31
|
+
# #compare_by_identity makes such owners different hash keys
|
32
|
+
@records_by_owner ||= preloaded_records.each_with_object({}.compare_by_identity) do |record, result|
|
31
33
|
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
32
34
|
(result[owner] ||= []) << record
|
33
35
|
end
|
@@ -46,7 +46,6 @@ module ActiveRecord
|
|
46
46
|
end
|
47
47
|
|
48
48
|
private
|
49
|
-
|
50
49
|
def load_schema!
|
51
50
|
super
|
52
51
|
attribute_types.each do |name, type|
|
@@ -75,7 +74,6 @@ module ActiveRecord
|
|
75
74
|
end
|
76
75
|
|
77
76
|
private
|
78
|
-
|
79
77
|
def decorators_for(name, type)
|
80
78
|
matching(name, type).map(&:last)
|
81
79
|
end
|
@@ -159,57 +159,6 @@ module ActiveRecord
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
-
# Regexp for column names (with or without a table name prefix). Matches
|
163
|
-
# the following:
|
164
|
-
# "#{table_name}.#{column_name}"
|
165
|
-
# "#{column_name}"
|
166
|
-
COLUMN_NAME = /\A(?:\w+\.)?\w+\z/i
|
167
|
-
|
168
|
-
# Regexp for column names with order (with or without a table name
|
169
|
-
# prefix, with or without various order modifiers). Matches the following:
|
170
|
-
# "#{table_name}.#{column_name}"
|
171
|
-
# "#{table_name}.#{column_name} #{direction}"
|
172
|
-
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
173
|
-
# "#{table_name}.#{column_name} NULLS LAST"
|
174
|
-
# "#{column_name}"
|
175
|
-
# "#{column_name} #{direction}"
|
176
|
-
# "#{column_name} #{direction} NULLS FIRST"
|
177
|
-
# "#{column_name} NULLS LAST"
|
178
|
-
COLUMN_NAME_WITH_ORDER = /
|
179
|
-
\A
|
180
|
-
(?:\w+\.)?
|
181
|
-
\w+
|
182
|
-
(?:\s+asc|\s+desc)?
|
183
|
-
(?:\s+nulls\s+(?:first|last))?
|
184
|
-
\z
|
185
|
-
/ix
|
186
|
-
|
187
|
-
def disallow_raw_sql!(args, permit: COLUMN_NAME) # :nodoc:
|
188
|
-
unexpected = args.reject do |arg|
|
189
|
-
Arel.arel_node?(arg) ||
|
190
|
-
arg.to_s.split(/\s*,\s*/).all? { |part| permit.match?(part) }
|
191
|
-
end
|
192
|
-
|
193
|
-
return if unexpected.none?
|
194
|
-
|
195
|
-
if allow_unsafe_raw_sql == :deprecated
|
196
|
-
ActiveSupport::Deprecation.warn(
|
197
|
-
"Dangerous query method (method whose arguments are used as raw " \
|
198
|
-
"SQL) called with non-attribute argument(s): " \
|
199
|
-
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
200
|
-
"arguments will be disallowed in Rails 6.1. This method should " \
|
201
|
-
"not be called with user-provided values, such as request " \
|
202
|
-
"parameters or model attributes. Known-safe values can be passed " \
|
203
|
-
"by wrapping them in Arel.sql()."
|
204
|
-
)
|
205
|
-
else
|
206
|
-
raise(ActiveRecord::UnknownAttributeReference,
|
207
|
-
"Query method called with non-attribute argument(s): " +
|
208
|
-
unexpected.map(&:inspect).join(", ")
|
209
|
-
)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
162
|
# Returns true if the given attribute exists, otherwise false.
|
214
163
|
#
|
215
164
|
# class Person < ActiveRecord::Base
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
# +to+ When passed, this method will return false unless the value was
|
50
50
|
# changed to the given value
|
51
51
|
def saved_change_to_attribute?(attr_name, **options)
|
52
|
-
mutations_before_last_save.changed?(attr_name.to_s, options)
|
52
|
+
mutations_before_last_save.changed?(attr_name.to_s, **options)
|
53
53
|
end
|
54
54
|
|
55
55
|
# Returns the change to an attribute during the last save. If the
|
@@ -99,7 +99,7 @@ module ActiveRecord
|
|
99
99
|
# +to+ When passed, this method will return false unless the value will be
|
100
100
|
# changed to the given value
|
101
101
|
def will_save_change_to_attribute?(attr_name, **options)
|
102
|
-
mutations_from_database.changed?(attr_name.to_s, options)
|
102
|
+
mutations_from_database.changed?(attr_name.to_s, **options)
|
103
103
|
end
|
104
104
|
|
105
105
|
# Returns the change to an attribute that will be persisted during the
|
@@ -177,6 +177,11 @@ module ActiveRecord
|
|
177
177
|
|
178
178
|
affected_rows = super
|
179
179
|
|
180
|
+
if @_skip_dirty_tracking ||= false
|
181
|
+
clear_attribute_changes(@_touch_attr_names)
|
182
|
+
return affected_rows
|
183
|
+
end
|
184
|
+
|
180
185
|
changes = {}
|
181
186
|
@attributes.keys.each do |attr_name|
|
182
187
|
next if @_touch_attr_names.include?(attr_name)
|
@@ -193,7 +198,7 @@ module ActiveRecord
|
|
193
198
|
|
194
199
|
affected_rows
|
195
200
|
ensure
|
196
|
-
@_touch_attr_names = nil
|
201
|
+
@_touch_attr_names, @_skip_dirty_tracking = nil, nil
|
197
202
|
end
|
198
203
|
|
199
204
|
def _update_record(attribute_names = attribute_names_for_partial_writes)
|
@@ -45,7 +45,6 @@ module ActiveRecord
|
|
45
45
|
end
|
46
46
|
|
47
47
|
private
|
48
|
-
|
49
48
|
def attribute_method?(attr_name)
|
50
49
|
attr_name == "id" || super
|
51
50
|
end
|
@@ -120,7 +119,6 @@ module ActiveRecord
|
|
120
119
|
end
|
121
120
|
|
122
121
|
private
|
123
|
-
|
124
122
|
def suppress_composite_primary_key(pk)
|
125
123
|
return pk unless pk.is_a?(Array)
|
126
124
|
|
@@ -25,7 +25,6 @@ module ActiveRecord
|
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
28
|
-
|
29
28
|
def convert_time_to_time_zone(value)
|
30
29
|
return if value.nil?
|
31
30
|
|
@@ -64,7 +63,6 @@ module ActiveRecord
|
|
64
63
|
|
65
64
|
module ClassMethods # :nodoc:
|
66
65
|
private
|
67
|
-
|
68
66
|
def inherited(subclass)
|
69
67
|
super
|
70
68
|
# We need to apply this decorator here, rather than on module inclusion. The closure
|
@@ -147,7 +147,6 @@ module ActiveRecord
|
|
147
147
|
|
148
148
|
module ClassMethods # :nodoc:
|
149
149
|
private
|
150
|
-
|
151
150
|
def define_non_cyclic_method(name, &block)
|
152
151
|
return if instance_methods(false).include?(name)
|
153
152
|
define_method(name) do |*args|
|
@@ -267,12 +266,11 @@ module ActiveRecord
|
|
267
266
|
end
|
268
267
|
|
269
268
|
private
|
270
|
-
|
271
269
|
# Returns the record for an association collection that should be validated
|
272
270
|
# or saved. If +autosave+ is +false+ only new records will be returned,
|
273
271
|
# unless the parent is/was a new record itself.
|
274
272
|
def associated_records_to_validate_or_save(association, new_record, autosave)
|
275
|
-
if new_record
|
273
|
+
if new_record || custom_validation_context?
|
276
274
|
association && association.target
|
277
275
|
elsif autosave
|
278
276
|
association.target.find_all(&:changed_for_autosave?)
|
@@ -304,7 +302,7 @@ module ActiveRecord
|
|
304
302
|
def validate_single_association(reflection)
|
305
303
|
association = association_instance_get(reflection.name)
|
306
304
|
record = association && association.reader
|
307
|
-
association_valid?(reflection, record) if record
|
305
|
+
association_valid?(reflection, record) if record && (record.changed_for_autosave? || custom_validation_context?)
|
308
306
|
end
|
309
307
|
|
310
308
|
# Validate the associated records if <tt>:validate</tt> or
|
@@ -324,7 +322,7 @@ module ActiveRecord
|
|
324
322
|
def association_valid?(reflection, record, index = nil)
|
325
323
|
return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
|
326
324
|
|
327
|
-
context = validation_context
|
325
|
+
context = validation_context if custom_validation_context?
|
328
326
|
|
329
327
|
unless valid = record.valid?(context)
|
330
328
|
if reflection.options[:autosave]
|
@@ -363,7 +361,9 @@ module ActiveRecord
|
|
363
361
|
# Is used as a before_save callback to check while saving a collection
|
364
362
|
# association whether or not the parent was a new record before saving.
|
365
363
|
def before_save_collection_association
|
366
|
-
@new_record_before_save
|
364
|
+
unless defined?(@new_record_before_save)
|
365
|
+
@new_record_before_save = new_record?
|
366
|
+
end
|
367
367
|
end
|
368
368
|
|
369
369
|
def after_save_collection_association
|
@@ -416,7 +416,7 @@ module ActiveRecord
|
|
416
416
|
saved = record.save(validate: false)
|
417
417
|
end
|
418
418
|
|
419
|
-
raise
|
419
|
+
raise(RecordInvalid.new(association.owner)) unless saved
|
420
420
|
end
|
421
421
|
end
|
422
422
|
end
|
@@ -499,6 +499,10 @@ module ActiveRecord
|
|
499
499
|
end
|
500
500
|
end
|
501
501
|
|
502
|
+
def custom_validation_context?
|
503
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
504
|
+
end
|
505
|
+
|
502
506
|
def _ensure_no_duplicate_errors
|
503
507
|
errors.messages.each_key do |attribute|
|
504
508
|
errors[attribute].uniq!
|