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.

Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +783 -910
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +22 -14
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +43 -26
  9. data/lib/active_record/associations/association_scope.rb +11 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  12. data/lib/active_record/associations/builder/association.rb +9 -3
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +19 -13
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +13 -5
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +114 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +64 -54
  43. data/lib/active_record/attributes.rb +32 -7
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +2 -24
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  91. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  93. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  94. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  95. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
  96. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  98. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  99. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  100. data/lib/active_record/connection_adapters.rb +50 -0
  101. data/lib/active_record/connection_handling.rb +210 -71
  102. data/lib/active_record/core.rb +223 -66
  103. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  104. data/lib/active_record/database_configurations/database_config.rb +52 -9
  105. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  106. data/lib/active_record/database_configurations/url_config.rb +15 -40
  107. data/lib/active_record/database_configurations.rb +124 -85
  108. data/lib/active_record/delegated_type.rb +209 -0
  109. data/lib/active_record/destroy_association_async_job.rb +36 -0
  110. data/lib/active_record/enum.rb +27 -10
  111. data/lib/active_record/errors.rb +47 -12
  112. data/lib/active_record/explain.rb +9 -4
  113. data/lib/active_record/explain_subscriber.rb +1 -1
  114. data/lib/active_record/fixture_set/file.rb +10 -17
  115. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  116. data/lib/active_record/fixture_set/render_context.rb +1 -1
  117. data/lib/active_record/fixture_set/table_row.rb +2 -2
  118. data/lib/active_record/fixtures.rb +54 -8
  119. data/lib/active_record/gem_version.rb +2 -2
  120. data/lib/active_record/inheritance.rb +40 -18
  121. data/lib/active_record/insert_all.rb +34 -5
  122. data/lib/active_record/integration.rb +3 -5
  123. data/lib/active_record/internal_metadata.rb +16 -7
  124. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  125. data/lib/active_record/locking/optimistic.rb +13 -16
  126. data/lib/active_record/locking/pessimistic.rb +6 -2
  127. data/lib/active_record/log_subscriber.rb +26 -8
  128. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  129. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/migration/command_recorder.rb +47 -27
  132. data/lib/active_record/migration/compatibility.rb +67 -17
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/model_schema.rb +88 -13
  135. data/lib/active_record/nested_attributes.rb +2 -3
  136. data/lib/active_record/no_touching.rb +1 -1
  137. data/lib/active_record/persistence.rb +50 -45
  138. data/lib/active_record/query_cache.rb +15 -5
  139. data/lib/active_record/querying.rb +11 -6
  140. data/lib/active_record/railtie.rb +64 -44
  141. data/lib/active_record/railties/databases.rake +266 -95
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +100 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/query_methods.rb +318 -195
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  158. data/lib/active_record/relation/where_clause.rb +104 -57
  159. data/lib/active_record/relation.rb +90 -64
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +2 -8
  165. data/lib/active_record/scoping/named.rb +1 -17
  166. data/lib/active_record/secure_token.rb +16 -8
  167. data/lib/active_record/serialization.rb +5 -3
  168. data/lib/active_record/signed_id.rb +116 -0
  169. data/lib/active_record/statement_cache.rb +20 -4
  170. data/lib/active_record/store.rb +2 -2
  171. data/lib/active_record/suppressor.rb +2 -2
  172. data/lib/active_record/table_metadata.rb +39 -51
  173. data/lib/active_record/tasks/database_tasks.rb +139 -113
  174. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  175. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  176. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  177. data/lib/active_record/test_databases.rb +5 -4
  178. data/lib/active_record/test_fixtures.rb +36 -33
  179. data/lib/active_record/timestamp.rb +4 -6
  180. data/lib/active_record/touch_later.rb +21 -21
  181. data/lib/active_record/transactions.rb +15 -64
  182. data/lib/active_record/type/serialized.rb +6 -2
  183. data/lib/active_record/type.rb +8 -1
  184. data/lib/active_record/type_caster/connection.rb +0 -1
  185. data/lib/active_record/type_caster/map.rb +8 -5
  186. data/lib/active_record/validations/associated.rb +1 -1
  187. data/lib/active_record/validations/numericality.rb +35 -0
  188. data/lib/active_record/validations/uniqueness.rb +24 -4
  189. data/lib/active_record/validations.rb +1 -0
  190. data/lib/active_record.rb +7 -14
  191. data/lib/arel/attributes/attribute.rb +4 -0
  192. data/lib/arel/collectors/bind.rb +5 -0
  193. data/lib/arel/collectors/composite.rb +8 -0
  194. data/lib/arel/collectors/sql_string.rb +7 -0
  195. data/lib/arel/collectors/substitute_binds.rb +7 -0
  196. data/lib/arel/nodes/binary.rb +82 -8
  197. data/lib/arel/nodes/bind_param.rb +8 -0
  198. data/lib/arel/nodes/casted.rb +21 -9
  199. data/lib/arel/nodes/equality.rb +6 -9
  200. data/lib/arel/nodes/grouping.rb +3 -0
  201. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  202. data/lib/arel/nodes/in.rb +8 -1
  203. data/lib/arel/nodes/infix_operation.rb +13 -1
  204. data/lib/arel/nodes/join_source.rb +1 -1
  205. data/lib/arel/nodes/node.rb +7 -6
  206. data/lib/arel/nodes/ordering.rb +27 -0
  207. data/lib/arel/nodes/sql_literal.rb +3 -0
  208. data/lib/arel/nodes/table_alias.rb +7 -3
  209. data/lib/arel/nodes/unary.rb +0 -1
  210. data/lib/arel/nodes.rb +3 -1
  211. data/lib/arel/predications.rb +12 -18
  212. data/lib/arel/select_manager.rb +1 -2
  213. data/lib/arel/table.rb +13 -5
  214. data/lib/arel/visitors/dot.rb +14 -2
  215. data/lib/arel/visitors/mysql.rb +11 -1
  216. data/lib/arel/visitors/postgresql.rb +15 -4
  217. data/lib/arel/visitors/to_sql.rb +89 -78
  218. data/lib/arel/visitors.rb +0 -7
  219. data/lib/arel.rb +5 -13
  220. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  221. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  222. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  223. data/lib/rails/generators/active_record/migration.rb +6 -1
  224. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  225. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  226. metadata +28 -30
  227. data/lib/active_record/advisory_lock_base.rb +0 -18
  228. data/lib/active_record/attribute_decorators.rb +0 -88
  229. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  230. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  231. data/lib/active_record/define_callbacks.rb +0 -22
  232. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  233. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  234. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  235. data/lib/arel/attributes.rb +0 -22
  236. data/lib/arel/visitors/depth_first.rb +0 -203
  237. data/lib/arel/visitors/ibm_db.rb +0 -34
  238. data/lib/arel/visitors/informix.rb +0 -62
  239. data/lib/arel/visitors/mssql.rb +0 -156
  240. data/lib/arel/visitors/oracle.rb +0 -158
  241. data/lib/arel/visitors/oracle12.rb +0 -65
  242. 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
- method_defined_within?(name, Base)
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) || class_method_defined_within?(method_name, Base)
119
- end
128
+ return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
120
129
 
121
- def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
122
- if klass.respond_to?(name, true)
123
- if superklass.respond_to?(name, true)
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.sub(/=$/, "")))
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') # => true
168
- # Person.has_attribute?(:age) # => true
169
- # Person.has_attribute?(:nothing) # => false
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
- attribute_types.key?(attr_name.to_s)
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
- # Returns the column object for the named attribute.
175
- # Returns a +ActiveRecord::ConnectionAdapters::NullColumn+ if the
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 has_attribute?(name)
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) # => true
234
- # person.has_attribute?('age') # => true
235
- # person.has_attribute?(:nothing) # => false
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
- @attributes.key?(attr_name.to_s)
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?(attribute)
301
- value = _read_attribute(attribute)
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.each_with_object({}) do |name, attrs|
381
- attrs[name] = _read_attribute(name)
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.is_a?(String) && value.length > 50
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
- end
410
- end
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
- def readonly_attribute?(name)
413
- self.class.readonly_attributes.include?(name)
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 = Type::Value.new, **options)
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
- if type.is_a?(Symbol)
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, before
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
- # post.save # => saves both post and comment
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
- # post.comments[0].body = 'hi everyone'
106
+ # comment = post.comments.create(body: 'hello world')
107
+ # comment.body = 'hi everyone'
107
108
  # post.comments.build(body: "good morning.")
108
- # post.title += "!"
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 instance_methods(false).include?(name)
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
- # go through nested autosave associations that are loaded in memory (without loading
282
- # any new ones), and return true if is changed for autosave
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 do |attribute, message|
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
- record.errors.details[attribute].each do |error|
341
- errors.details[reflection_attribute] << error
342
- errors.details[reflection_attribute].uniq!
343
- end
344
- end
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] ? send(reflection.options[:primary_key]) : id
460
+ key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
442
461
 
443
- if (autosave && record.changed_for_autosave?) || new_record? || record_changed?(reflection, record, key)
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.has_attribute?(reflection.foreign_key) && record[reflection.foreign_key] != key
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.send(reflection.options[:primary_key] || :id)
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.messages.each_key do |attribute|
506
- errors[attribute].uniq!
507
- end
524
+ errors.uniq!
508
525
  end
509
526
  end
510
527
  end
@@ -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