activerecord 6.0.6 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +28 -30
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "mutex_m"
|
4
|
+
require "active_support/core_ext/enumerable"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
# = Active Record Attribute Methods
|
@@ -18,8 +19,6 @@ module ActiveRecord
|
|
18
19
|
include TimeZoneConversion
|
19
20
|
include Dirty
|
20
21
|
include Serialization
|
21
|
-
|
22
|
-
delegate :column_for_attribute, to: :class
|
23
22
|
end
|
24
23
|
|
25
24
|
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
@@ -28,6 +27,17 @@ module ActiveRecord
|
|
28
27
|
include Mutex_m
|
29
28
|
end
|
30
29
|
|
30
|
+
class << self
|
31
|
+
def dangerous_attribute_methods # :nodoc:
|
32
|
+
@dangerous_attribute_methods ||= (
|
33
|
+
Base.instance_methods +
|
34
|
+
Base.private_instance_methods -
|
35
|
+
Base.superclass.instance_methods -
|
36
|
+
Base.superclass.private_instance_methods
|
37
|
+
).map { |m| -m.to_s }.to_set.freeze
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
31
41
|
module ClassMethods
|
32
42
|
def inherited(child_class) #:nodoc:
|
33
43
|
child_class.initialize_generated_modules
|
@@ -97,7 +107,7 @@ module ActiveRecord
|
|
97
107
|
# A method name is 'dangerous' if it is already (re)defined by Active Record, but
|
98
108
|
# not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
|
99
109
|
def dangerous_attribute_method?(name) # :nodoc:
|
100
|
-
|
110
|
+
::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(name.to_s)
|
101
111
|
end
|
102
112
|
|
103
113
|
def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
|
@@ -115,13 +125,11 @@ module ActiveRecord
|
|
115
125
|
# A class method is 'dangerous' if it is already (re)defined by Active Record, but
|
116
126
|
# not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
|
117
127
|
def dangerous_class_method?(method_name)
|
118
|
-
RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
|
119
|
-
end
|
128
|
+
return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
|
120
129
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
klass.method(name).owner != superklass.method(name).owner
|
130
|
+
if Base.respond_to?(method_name, true)
|
131
|
+
if Object.respond_to?(method_name, true)
|
132
|
+
Base.method(method_name).owner != Object.method(method_name).owner
|
125
133
|
else
|
126
134
|
true
|
127
135
|
end
|
@@ -140,7 +148,7 @@ module ActiveRecord
|
|
140
148
|
# Person.attribute_method?(:age=) # => true
|
141
149
|
# Person.attribute_method?(:nothing) # => false
|
142
150
|
def attribute_method?(attribute)
|
143
|
-
super || (table_exists? && column_names.include?(attribute.to_s.
|
151
|
+
super || (table_exists? && column_names.include?(attribute.to_s.delete_suffix("=")))
|
144
152
|
end
|
145
153
|
|
146
154
|
# Returns an array of column names as strings if it's not an abstract class and
|
@@ -156,39 +164,27 @@ module ActiveRecord
|
|
156
164
|
attribute_types.keys
|
157
165
|
else
|
158
166
|
[]
|
159
|
-
end
|
167
|
+
end.freeze
|
160
168
|
end
|
161
169
|
|
162
170
|
# Returns true if the given attribute exists, otherwise false.
|
163
171
|
#
|
164
172
|
# class Person < ActiveRecord::Base
|
173
|
+
# alias_attribute :new_name, :name
|
165
174
|
# end
|
166
175
|
#
|
167
|
-
# Person.has_attribute?('name')
|
168
|
-
# Person.has_attribute?(
|
169
|
-
# Person.has_attribute?(:
|
176
|
+
# Person.has_attribute?('name') # => true
|
177
|
+
# Person.has_attribute?('new_name') # => true
|
178
|
+
# Person.has_attribute?(:age) # => true
|
179
|
+
# Person.has_attribute?(:nothing) # => false
|
170
180
|
def has_attribute?(attr_name)
|
171
|
-
|
181
|
+
attr_name = attr_name.to_s
|
182
|
+
attr_name = attribute_aliases[attr_name] || attr_name
|
183
|
+
attribute_types.key?(attr_name)
|
172
184
|
end
|
173
185
|
|
174
|
-
|
175
|
-
|
176
|
-
# named attribute does not exist.
|
177
|
-
#
|
178
|
-
# class Person < ActiveRecord::Base
|
179
|
-
# end
|
180
|
-
#
|
181
|
-
# person = Person.new
|
182
|
-
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
|
183
|
-
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
184
|
-
#
|
185
|
-
# person.column_for_attribute(:nothing)
|
186
|
-
# # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
|
187
|
-
def column_for_attribute(name)
|
188
|
-
name = name.to_s
|
189
|
-
columns_hash.fetch(name) do
|
190
|
-
ConnectionAdapters::NullColumn.new(name)
|
191
|
-
end
|
186
|
+
def _has_attribute?(attr_name) # :nodoc:
|
187
|
+
attribute_types.key?(attr_name)
|
192
188
|
end
|
193
189
|
end
|
194
190
|
|
@@ -217,7 +213,7 @@ module ActiveRecord
|
|
217
213
|
# have been allocated but not yet initialized.
|
218
214
|
if defined?(@attributes)
|
219
215
|
if name = self.class.symbol_column_to_string(name.to_sym)
|
220
|
-
return
|
216
|
+
return _has_attribute?(name)
|
221
217
|
end
|
222
218
|
end
|
223
219
|
|
@@ -227,14 +223,22 @@ module ActiveRecord
|
|
227
223
|
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
|
228
224
|
#
|
229
225
|
# class Person < ActiveRecord::Base
|
226
|
+
# alias_attribute :new_name, :name
|
230
227
|
# end
|
231
228
|
#
|
232
229
|
# person = Person.new
|
233
|
-
# person.has_attribute?(:name)
|
234
|
-
# person.has_attribute?(
|
235
|
-
# person.has_attribute?(
|
230
|
+
# person.has_attribute?(:name) # => true
|
231
|
+
# person.has_attribute?(:new_name) # => true
|
232
|
+
# person.has_attribute?('age') # => true
|
233
|
+
# person.has_attribute?(:nothing) # => false
|
236
234
|
def has_attribute?(attr_name)
|
237
|
-
|
235
|
+
attr_name = attr_name.to_s
|
236
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
237
|
+
@attributes.key?(attr_name)
|
238
|
+
end
|
239
|
+
|
240
|
+
def _has_attribute?(attr_name) # :nodoc:
|
241
|
+
@attributes.key?(attr_name)
|
238
242
|
end
|
239
243
|
|
240
244
|
# Returns an array of names for the attributes available on this object.
|
@@ -278,8 +282,10 @@ module ActiveRecord
|
|
278
282
|
# person.attribute_for_inspect(:tag_ids)
|
279
283
|
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
280
284
|
def attribute_for_inspect(attr_name)
|
285
|
+
attr_name = attr_name.to_s
|
286
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
281
287
|
value = _read_attribute(attr_name)
|
282
|
-
format_for_inspect(value)
|
288
|
+
format_for_inspect(attr_name, value)
|
283
289
|
end
|
284
290
|
|
285
291
|
# Returns +true+ if the specified +attribute+ has been set by the user or by a
|
@@ -297,8 +303,10 @@ module ActiveRecord
|
|
297
303
|
# task.is_done = true
|
298
304
|
# task.attribute_present?(:title) # => true
|
299
305
|
# task.attribute_present?(:is_done) # => true
|
300
|
-
def attribute_present?(
|
301
|
-
|
306
|
+
def attribute_present?(attr_name)
|
307
|
+
attr_name = attr_name.to_s
|
308
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
309
|
+
value = _read_attribute(attr_name)
|
302
310
|
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
303
311
|
end
|
304
312
|
|
@@ -377,8 +385,8 @@ module ActiveRecord
|
|
377
385
|
end
|
378
386
|
|
379
387
|
def attributes_with_values(attribute_names)
|
380
|
-
attribute_names.
|
381
|
-
|
388
|
+
attribute_names.index_with do |name|
|
389
|
+
_read_attribute(name)
|
382
390
|
end
|
383
391
|
end
|
384
392
|
|
@@ -386,7 +394,7 @@ module ActiveRecord
|
|
386
394
|
def attributes_for_update(attribute_names)
|
387
395
|
attribute_names &= self.class.column_names
|
388
396
|
attribute_names.delete_if do |name|
|
389
|
-
readonly_attribute?(name)
|
397
|
+
self.class.readonly_attribute?(name)
|
390
398
|
end
|
391
399
|
end
|
392
400
|
|
@@ -399,18 +407,20 @@ module ActiveRecord
|
|
399
407
|
end
|
400
408
|
end
|
401
409
|
|
402
|
-
def format_for_inspect(value)
|
403
|
-
if value.
|
404
|
-
"#{value[0, 50]}...".inspect
|
405
|
-
elsif value.is_a?(Date) || value.is_a?(Time)
|
406
|
-
%("#{value.to_s(:db)}")
|
407
|
-
else
|
410
|
+
def format_for_inspect(name, value)
|
411
|
+
if value.nil?
|
408
412
|
value.inspect
|
409
|
-
|
410
|
-
|
413
|
+
else
|
414
|
+
inspected_value = if value.is_a?(String) && value.length > 50
|
415
|
+
"#{value[0, 50]}...".inspect
|
416
|
+
elsif value.is_a?(Date) || value.is_a?(Time)
|
417
|
+
%("#{value.to_s(:inspect)}")
|
418
|
+
else
|
419
|
+
value.inspect
|
420
|
+
end
|
411
421
|
|
412
|
-
|
413
|
-
|
422
|
+
inspection_filter.filter_param(name, inspected_value)
|
423
|
+
end
|
414
424
|
end
|
415
425
|
|
416
426
|
def pk_attribute?(name)
|
@@ -12,6 +12,9 @@ module ActiveRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
+
##
|
16
|
+
# :call-seq: attribute(name, cast_type = nil, **options)
|
17
|
+
#
|
15
18
|
# Defines an attribute with a type on this model. It will override the
|
16
19
|
# type of existing attributes if needed. This allows control over how
|
17
20
|
# values are converted to and from SQL when assigned to a model. It also
|
@@ -205,13 +208,13 @@ module ActiveRecord
|
|
205
208
|
# tracking is performed. The methods +changed?+ and +changed_in_place?+
|
206
209
|
# will be called from ActiveModel::Dirty. See the documentation for those
|
207
210
|
# methods in ActiveModel::Type::Value for more details.
|
208
|
-
def attribute(name, cast_type =
|
211
|
+
def attribute(name, cast_type = nil, **options, &block)
|
209
212
|
name = name.to_s
|
210
213
|
reload_schema_from_cache
|
211
214
|
|
212
215
|
self.attributes_to_define_after_schema_loads =
|
213
216
|
attributes_to_define_after_schema_loads.merge(
|
214
|
-
name => [cast_type, options]
|
217
|
+
name => [cast_type || block, options]
|
215
218
|
)
|
216
219
|
end
|
217
220
|
|
@@ -246,11 +249,7 @@ module ActiveRecord
|
|
246
249
|
def load_schema! # :nodoc:
|
247
250
|
super
|
248
251
|
attributes_to_define_after_schema_loads.each do |name, (type, options)|
|
249
|
-
|
250
|
-
type = ActiveRecord::Type.lookup(type, **options.except(:default))
|
251
|
-
end
|
252
|
-
|
253
|
-
define_attribute(name, type, **options.slice(:default))
|
252
|
+
define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
|
254
253
|
end
|
255
254
|
end
|
256
255
|
|
@@ -273,6 +272,32 @@ module ActiveRecord
|
|
273
272
|
end
|
274
273
|
_default_attributes[name] = default_attribute
|
275
274
|
end
|
275
|
+
|
276
|
+
def decorate_attribute_type(attr_name, **default)
|
277
|
+
type, options = attributes_to_define_after_schema_loads[attr_name]
|
278
|
+
|
279
|
+
default.with_defaults!(default: options[:default]) if options&.key?(:default)
|
280
|
+
|
281
|
+
attribute(attr_name, **default) do |cast_type|
|
282
|
+
if type && !type.is_a?(Proc)
|
283
|
+
cast_type = _lookup_cast_type(attr_name, type, options)
|
284
|
+
end
|
285
|
+
|
286
|
+
yield cast_type
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def _lookup_cast_type(name, type, options)
|
291
|
+
case type
|
292
|
+
when Symbol
|
293
|
+
adapter_name = ActiveRecord::Type.adapter_name_from(self)
|
294
|
+
ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
|
295
|
+
when Proc
|
296
|
+
type[type_for_attribute(name)]
|
297
|
+
else
|
298
|
+
type || type_for_attribute(name)
|
299
|
+
end
|
300
|
+
end
|
276
301
|
end
|
277
302
|
end
|
278
303
|
end
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
# Association with autosave option defines several callbacks on your
|
32
32
|
# model (around_save, before_save, after_create, after_update). Please note that
|
33
33
|
# callbacks are executed in the order they were defined in
|
34
|
-
# model. You should avoid modifying the association content
|
34
|
+
# model. You should avoid modifying the association content before
|
35
35
|
# autosave callbacks are executed. Placing your callbacks after
|
36
36
|
# associations is usually a good practice.
|
37
37
|
#
|
@@ -91,8 +91,9 @@ module ActiveRecord
|
|
91
91
|
# post.save # => saves both post and comment
|
92
92
|
#
|
93
93
|
# post = Post.create(title: 'ruby rocks')
|
94
|
-
# post.comments.create(body: 'hello world')
|
95
|
-
#
|
94
|
+
# comment = post.comments.create(body: 'hello world')
|
95
|
+
# comment.body = 'hi everyone'
|
96
|
+
# post.save # => saves post, but not comment
|
96
97
|
#
|
97
98
|
# When <tt>:autosave</tt> is true all children are saved, no matter whether they
|
98
99
|
# are new records or not:
|
@@ -102,11 +103,10 @@ module ActiveRecord
|
|
102
103
|
# end
|
103
104
|
#
|
104
105
|
# post = Post.create(title: 'ruby rocks')
|
105
|
-
# post.comments.create(body: 'hello world')
|
106
|
-
#
|
106
|
+
# comment = post.comments.create(body: 'hello world')
|
107
|
+
# comment.body = 'hi everyone'
|
107
108
|
# post.comments.build(body: "good morning.")
|
108
|
-
# post.
|
109
|
-
# post.save # => saves both post and comments.
|
109
|
+
# post.save # => saves post and both comments.
|
110
110
|
#
|
111
111
|
# Destroying one of the associated models as part of the parent's save action
|
112
112
|
# is as simple as marking it for destruction:
|
@@ -127,6 +127,14 @@ module ActiveRecord
|
|
127
127
|
# Now it _is_ removed from the database:
|
128
128
|
#
|
129
129
|
# Comment.find_by(id: id).nil? # => true
|
130
|
+
#
|
131
|
+
# === Caveats
|
132
|
+
#
|
133
|
+
# Note that autosave will only trigger for already-persisted association records
|
134
|
+
# if the records themselves have been changed. This is to protect against
|
135
|
+
# <tt>SystemStackError</tt> caused by circular association validations. The one
|
136
|
+
# exception is if a custom validation context is used, in which case the validations
|
137
|
+
# will always fire on the associated records.
|
130
138
|
module AutosaveAssociation
|
131
139
|
extend ActiveSupport::Concern
|
132
140
|
|
@@ -147,8 +155,23 @@ module ActiveRecord
|
|
147
155
|
|
148
156
|
module ClassMethods # :nodoc:
|
149
157
|
private
|
158
|
+
if Module.method(:method_defined?).arity == 1 # MRI 2.5 and older
|
159
|
+
using Module.new {
|
160
|
+
refine Module do
|
161
|
+
def method_defined?(method, inherit = true)
|
162
|
+
if inherit
|
163
|
+
super(method)
|
164
|
+
else
|
165
|
+
instance_methods(false).include?(method.to_sym)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
150
172
|
def define_non_cyclic_method(name, &block)
|
151
|
-
return if
|
173
|
+
return if method_defined?(name, false)
|
174
|
+
|
152
175
|
define_method(name) do |*args|
|
153
176
|
result = true; @_already_called ||= {}
|
154
177
|
# Loop prevention for validation of associations
|
@@ -278,8 +301,9 @@ module ActiveRecord
|
|
278
301
|
end
|
279
302
|
end
|
280
303
|
|
281
|
-
#
|
282
|
-
# any new ones), and return true if
|
304
|
+
# Go through nested autosave associations that are loaded in memory (without loading
|
305
|
+
# any new ones), and return true if any are changed for autosave.
|
306
|
+
# Returns false if already called to prevent an infinite loop.
|
283
307
|
def nested_records_changed_for_autosave?
|
284
308
|
@_nested_records_changed_for_autosave_already_called ||= false
|
285
309
|
return false if @_nested_records_changed_for_autosave_already_called
|
@@ -327,21 +351,16 @@ module ActiveRecord
|
|
327
351
|
if reflection.options[:autosave]
|
328
352
|
indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors)
|
329
353
|
|
330
|
-
record.errors.each
|
354
|
+
record.errors.group_by_attribute.each { |attribute, errors|
|
331
355
|
attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
|
332
|
-
errors[attribute] << message
|
333
|
-
errors[attribute].uniq!
|
334
|
-
end
|
335
|
-
|
336
|
-
record.errors.details.each_key do |attribute|
|
337
|
-
reflection_attribute =
|
338
|
-
normalize_reflection_attribute(indexed_attribute, reflection, index, attribute).to_sym
|
339
356
|
|
340
|
-
|
341
|
-
errors.
|
342
|
-
|
343
|
-
|
344
|
-
|
357
|
+
errors.each { |error|
|
358
|
+
self.errors.import(
|
359
|
+
error,
|
360
|
+
attribute: attribute
|
361
|
+
)
|
362
|
+
}
|
363
|
+
}
|
345
364
|
else
|
346
365
|
errors.add(reflection.name)
|
347
366
|
end
|
@@ -438,9 +457,9 @@ module ActiveRecord
|
|
438
457
|
if autosave && record.marked_for_destruction?
|
439
458
|
record.destroy
|
440
459
|
elsif autosave != false
|
441
|
-
key = reflection.options[:primary_key] ?
|
460
|
+
key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
|
442
461
|
|
443
|
-
if (autosave && record.changed_for_autosave?) ||
|
462
|
+
if (autosave && record.changed_for_autosave?) || record_changed?(reflection, record, key)
|
444
463
|
unless reflection.through_reflection
|
445
464
|
record[reflection.foreign_key] = key
|
446
465
|
if inverse_reflection = reflection.inverse_of
|
@@ -466,7 +485,7 @@ module ActiveRecord
|
|
466
485
|
def association_foreign_key_changed?(reflection, record, key)
|
467
486
|
return false if reflection.through_reflection?
|
468
487
|
|
469
|
-
record.
|
488
|
+
record._has_attribute?(reflection.foreign_key) && record._read_attribute(reflection.foreign_key) != key
|
470
489
|
end
|
471
490
|
|
472
491
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
@@ -487,7 +506,7 @@ module ActiveRecord
|
|
487
506
|
saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
|
488
507
|
|
489
508
|
if association.updated?
|
490
|
-
association_id = record.
|
509
|
+
association_id = record.public_send(reflection.options[:primary_key] || :id)
|
491
510
|
self[reflection.foreign_key] = association_id
|
492
511
|
association.loaded!
|
493
512
|
end
|
@@ -502,9 +521,7 @@ module ActiveRecord
|
|
502
521
|
end
|
503
522
|
|
504
523
|
def _ensure_no_duplicate_errors
|
505
|
-
errors.
|
506
|
-
errors[attribute].uniq!
|
507
|
-
end
|
524
|
+
errors.uniq!
|
508
525
|
end
|
509
526
|
end
|
510
527
|
end
|
data/lib/active_record/base.rb
CHANGED
@@ -1,22 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "yaml"
|
4
3
|
require "active_support/benchmarkable"
|
5
4
|
require "active_support/dependencies"
|
6
5
|
require "active_support/descendants_tracker"
|
7
6
|
require "active_support/time"
|
8
|
-
require "active_support/core_ext/module/attribute_accessors"
|
9
|
-
require "active_support/core_ext/array/extract_options"
|
10
|
-
require "active_support/core_ext/hash/deep_merge"
|
11
|
-
require "active_support/core_ext/hash/slice"
|
12
|
-
require "active_support/core_ext/string/behavior"
|
13
|
-
require "active_support/core_ext/kernel/singleton_class"
|
14
|
-
require "active_support/core_ext/module/introspection"
|
15
|
-
require "active_support/core_ext/object/duplicable"
|
16
7
|
require "active_support/core_ext/class/subclasses"
|
17
|
-
require "active_record/attribute_decorators"
|
18
|
-
require "active_record/define_callbacks"
|
19
|
-
require "active_record/errors"
|
20
8
|
require "active_record/log_subscriber"
|
21
9
|
require "active_record/explain_subscriber"
|
22
10
|
require "active_record/relation/delegation"
|
@@ -285,6 +273,7 @@ module ActiveRecord #:nodoc:
|
|
285
273
|
extend Querying
|
286
274
|
extend Translation
|
287
275
|
extend DynamicMatchers
|
276
|
+
extend DelegatedType
|
288
277
|
extend Explain
|
289
278
|
extend Enum
|
290
279
|
extend Delegation::DelegateCache
|
@@ -303,10 +292,8 @@ module ActiveRecord #:nodoc:
|
|
303
292
|
include Validations
|
304
293
|
include CounterCache
|
305
294
|
include Attributes
|
306
|
-
include AttributeDecorators
|
307
295
|
include Locking::Optimistic
|
308
296
|
include Locking::Pessimistic
|
309
|
-
include DefineCallbacks
|
310
297
|
include AttributeMethods
|
311
298
|
include Callbacks
|
312
299
|
include Timestamp
|
@@ -321,6 +308,7 @@ module ActiveRecord #:nodoc:
|
|
321
308
|
include Serialization
|
322
309
|
include Store
|
323
310
|
include SecureToken
|
311
|
+
include SignedId
|
324
312
|
include Suppressor
|
325
313
|
end
|
326
314
|
|