activerecord 6.1.4.6 → 7.0.2.3

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 (240) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1188 -932
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +33 -17
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +34 -27
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/join_dependency.rb +6 -2
  25. data/lib/active_record/associations/preloader/association.rb +187 -55
  26. data/lib/active_record/associations/preloader/batch.rb +48 -0
  27. data/lib/active_record/associations/preloader/branch.rb +147 -0
  28. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  29. data/lib/active_record/associations/preloader.rb +39 -113
  30. data/lib/active_record/associations/singular_association.rb +8 -2
  31. data/lib/active_record/associations/through_association.rb +3 -3
  32. data/lib/active_record/associations.rb +119 -90
  33. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  34. data/lib/active_record/attribute_assignment.rb +1 -1
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  37. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  38. data/lib/active_record/attribute_methods/query.rb +2 -2
  39. data/lib/active_record/attribute_methods/read.rb +7 -5
  40. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  42. data/lib/active_record/attribute_methods/write.rb +7 -10
  43. data/lib/active_record/attribute_methods.rb +13 -14
  44. data/lib/active_record/attributes.rb +24 -35
  45. data/lib/active_record/autosave_association.rb +8 -23
  46. data/lib/active_record/base.rb +19 -1
  47. data/lib/active_record/callbacks.rb +2 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +78 -22
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +38 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +5 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -50
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +35 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +27 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +16 -14
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +89 -30
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +47 -53
  94. data/lib/active_record/core.rb +122 -132
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +16 -32
  100. data/lib/active_record/delegated_type.rb +52 -11
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +61 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +49 -42
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +17 -20
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +3 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +9 -3
  147. data/lib/active_record/log_subscriber.rb +14 -3
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +8 -3
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +4 -4
  152. data/lib/active_record/migration/compatibility.rb +107 -3
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +109 -79
  155. data/lib/active_record/model_schema.rb +45 -58
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +219 -52
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +15 -5
  163. data/lib/active_record/railtie.rb +127 -17
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +66 -129
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +67 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +3 -3
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +249 -61
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +184 -84
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +11 -7
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +61 -12
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +1 -1
  191. data/lib/active_record/signed_id.rb +1 -1
  192. data/lib/active_record/suppressor.rb +11 -15
  193. data/lib/active_record/tasks/database_tasks.rb +120 -58
  194. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  195. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
  196. data/lib/active_record/test_databases.rb +1 -1
  197. data/lib/active_record/test_fixtures.rb +4 -4
  198. data/lib/active_record/timestamp.rb +3 -4
  199. data/lib/active_record/transactions.rb +9 -14
  200. data/lib/active_record/translation.rb +2 -2
  201. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  202. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  203. data/lib/active_record/type/internal/timezone.rb +2 -2
  204. data/lib/active_record/type/serialized.rb +1 -1
  205. data/lib/active_record/type/type_map.rb +17 -20
  206. data/lib/active_record/type.rb +1 -2
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/uniqueness.rb +1 -1
  209. data/lib/active_record.rb +204 -28
  210. data/lib/arel/attributes/attribute.rb +0 -8
  211. data/lib/arel/crud.rb +28 -22
  212. data/lib/arel/delete_manager.rb +18 -4
  213. data/lib/arel/filter_predications.rb +9 -0
  214. data/lib/arel/insert_manager.rb +2 -3
  215. data/lib/arel/nodes/casted.rb +1 -1
  216. data/lib/arel/nodes/delete_statement.rb +12 -13
  217. data/lib/arel/nodes/filter.rb +10 -0
  218. data/lib/arel/nodes/function.rb +1 -0
  219. data/lib/arel/nodes/insert_statement.rb +2 -2
  220. data/lib/arel/nodes/select_core.rb +2 -2
  221. data/lib/arel/nodes/select_statement.rb +2 -2
  222. data/lib/arel/nodes/update_statement.rb +8 -3
  223. data/lib/arel/nodes.rb +1 -0
  224. data/lib/arel/predications.rb +11 -3
  225. data/lib/arel/select_manager.rb +10 -4
  226. data/lib/arel/table.rb +0 -1
  227. data/lib/arel/tree_manager.rb +0 -12
  228. data/lib/arel/update_manager.rb +18 -4
  229. data/lib/arel/visitors/dot.rb +80 -90
  230. data/lib/arel/visitors/mysql.rb +8 -2
  231. data/lib/arel/visitors/postgresql.rb +0 -10
  232. data/lib/arel/visitors/to_sql.rb +58 -2
  233. data/lib/arel.rb +2 -1
  234. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  235. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  236. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  237. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  238. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  239. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  240. metadata +56 -11
@@ -6,11 +6,11 @@ module ActiveRecord
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- attribute_method_suffix "?"
9
+ attribute_method_suffix "?", parameters: false
10
10
  end
11
11
 
12
12
  def query_attribute(attr_name)
13
- value = self[attr_name]
13
+ value = self.public_send(attr_name)
14
14
 
15
15
  case value
16
16
  when true then true
@@ -11,10 +11,12 @@ module ActiveRecord
11
11
  ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
12
12
  owner, name
13
13
  ) do |temp_method_name, attr_name_expr|
14
- owner <<
15
- "def #{temp_method_name}" <<
16
- " _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
17
- "end"
14
+ owner.define_cached_method(name, as: temp_method_name, namespace: :active_record) do |batch|
15
+ batch <<
16
+ "def #{temp_method_name}" <<
17
+ " _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
18
+ "end"
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -32,7 +34,7 @@ module ActiveRecord
32
34
 
33
35
  # This method exists to avoid the expensive primary_key check internally, without
34
36
  # breaking compatibility with the read_attribute API
35
- def _read_attribute(attr_name, &block) # :nodoc
37
+ def _read_attribute(attr_name, &block) # :nodoc:
36
38
  @attributes.fetch_value(attr_name, &block)
37
39
  end
38
40
 
@@ -16,15 +16,45 @@ module ActiveRecord
16
16
  end
17
17
 
18
18
  module ClassMethods
19
- # If you have an attribute that needs to be saved to the database as an
20
- # object, and retrieved as the same object, then specify the name of that
21
- # attribute using this method and it will be handled automatically. The
22
- # serialization is done through YAML. If +class_name+ is specified, the
23
- # serialized object must be of that class on assignment and retrieval.
24
- # Otherwise SerializationTypeMismatch will be raised.
19
+ # If you have an attribute that needs to be saved to the database as a
20
+ # serialized object, and retrieved by deserializing into the same object,
21
+ # then specify the name of that attribute using this method and serialization
22
+ # will be handled automatically.
25
23
  #
26
- # Empty objects as <tt>{}</tt>, in the case of +Hash+, or <tt>[]</tt>, in the case of
27
- # +Array+, will always be persisted as null.
24
+ # The serialization format may be YAML, JSON, or any custom format using a
25
+ # custom coder class.
26
+ #
27
+ # === Serialization formats
28
+ #
29
+ # serialize attr_name [, class_name_or_coder]
30
+ #
31
+ # | | database storage |
32
+ # class_name_or_coder | attribute read/write type | serialized | NULL |
33
+ # ---------------------+---------------------------+------------+--------+
34
+ # <not given> | any value that supports | YAML | |
35
+ # | .to_yaml | | |
36
+ # | | | |
37
+ # Array | Array ** | YAML | [] |
38
+ # | | | |
39
+ # Hash | Hash ** | YAML | {} |
40
+ # | | | |
41
+ # JSON | any value that supports | JSON | |
42
+ # | .to_json | | |
43
+ # | | | |
44
+ # <custom coder class> | any value supported by | custom | custom |
45
+ # | the custom coder class | | |
46
+ #
47
+ # ** If +class_name_or_coder+ is +Array+ or +Hash+, values retrieved will
48
+ # always be of that type, and any value assigned must be of that type or
49
+ # +SerializationTypeMismatch+ will be raised.
50
+ #
51
+ # ==== Custom coders
52
+ # A custom coder class or module may be given. This must have +self.load+
53
+ # and +self.dump+ class/module methods. <tt>self.dump(object)</tt> will be called
54
+ # to serialize an object and should return the serialized value to be
55
+ # stored in the database (+nil+ to store as +NULL+). <tt>self.load(string)</tt>
56
+ # will be called to reverse the process and load (unserialize) from the
57
+ # database.
28
58
  #
29
59
  # Keep in mind that database adapters handle certain serialization tasks
30
60
  # for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be
@@ -38,8 +68,9 @@ module ActiveRecord
38
68
  # ==== Parameters
39
69
  #
40
70
  # * +attr_name+ - The field name that should be serialized.
41
- # * +class_name_or_coder+ - Optional, a coder object, which responds to +.load+ and +.dump+
42
- # or a class name that the object type should be equal to.
71
+ # * +class_name_or_coder+ - Optional, may be be +Array+ or +Hash+ or
72
+ # +JSON+ or a custom coder class or module which responds to +.load+
73
+ # and +.dump+. See table above.
43
74
  #
44
75
  # ==== Options
45
76
  #
@@ -49,7 +80,7 @@ module ActiveRecord
49
80
  #
50
81
  # ==== Example
51
82
  #
52
- # # Serialize a preferences attribute.
83
+ # # Serialize a preferences attribute using YAML coder.
53
84
  # class User < ActiveRecord::Base
54
85
  # serialize :preferences
55
86
  # end
@@ -63,6 +94,28 @@ module ActiveRecord
63
94
  # class User < ActiveRecord::Base
64
95
  # serialize :preferences, Hash
65
96
  # end
97
+ #
98
+ # # Serialize preferences using a custom coder.
99
+ # class Rot13JSON
100
+ # def self.rot13(string)
101
+ # string.tr("a-zA-Z", "n-za-mN-ZA-M")
102
+ # end
103
+ #
104
+ # # returns serialized string that will be stored in the database
105
+ # def self.dump(object)
106
+ # ActiveSupport::JSON.encode(object).rot13
107
+ # end
108
+ #
109
+ # # reverses the above, turning the serialized string from the database
110
+ # # back into its original value
111
+ # def self.load(string)
112
+ # ActiveSupport::JSON.decode(string.rot13)
113
+ # end
114
+ # end
115
+ #
116
+ # class User < ActiveRecord::Base
117
+ # serialize :preferences, Rot13JSON
118
+ # end
66
119
  def serialize(attr_name, class_name_or_coder = Object, **options)
67
120
  # When ::JSON is used, force it to go through the Active Support JSON encoder
68
121
  # to ensure special objects (e.g. Active Record models) are dumped correctly
@@ -75,11 +128,12 @@ module ActiveRecord
75
128
  Coders::YAMLColumn.new(attr_name, class_name_or_coder)
76
129
  end
77
130
 
78
- decorate_attribute_type(attr_name.to_s, **options) do |cast_type|
131
+ attribute(attr_name, **options) do |cast_type|
79
132
  if type_incompatible_with_serialize?(cast_type, class_name_or_coder)
80
133
  raise ColumnNotSerializableError.new(attr_name, cast_type)
81
134
  end
82
135
 
136
+ cast_type = cast_type.subtype if Type::Serialized === cast_type
83
137
  Type::Serialized.new(cast_type, coder)
84
138
  end
85
139
  end
@@ -25,6 +25,8 @@ module ActiveRecord
25
25
  rescue ArgumentError
26
26
  nil
27
27
  end
28
+ elsif value.respond_to?(:infinite?) && value.infinite?
29
+ value
28
30
  else
29
31
  map_avoiding_infinite_recursion(super) { |v| cast(v) }
30
32
  end
@@ -36,7 +38,7 @@ module ActiveRecord
36
38
 
37
39
  if value.acts_like?(:time)
38
40
  value.in_time_zone
39
- elsif value.is_a?(::Float)
41
+ elsif value.respond_to?(:infinite?) && value.infinite?
40
42
  value
41
43
  else
42
44
  map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
@@ -61,8 +63,7 @@ module ActiveRecord
61
63
  extend ActiveSupport::Concern
62
64
 
63
65
  included do
64
- mattr_accessor :time_zone_aware_attributes, instance_writer: false, default: false
65
-
66
+ class_attribute :time_zone_aware_attributes, instance_writer: false, default: false
66
67
  class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false, default: []
67
68
  class_attribute :time_zone_aware_types, instance_writer: false, default: [ :datetime, :time ]
68
69
  end
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- attribute_method_suffix "="
9
+ attribute_method_suffix "=", parameters: "value"
10
10
  end
11
11
 
12
12
  module ClassMethods # :nodoc:
@@ -15,10 +15,12 @@ module ActiveRecord
15
15
  ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
16
16
  owner, name, writer: true,
17
17
  ) do |temp_method_name, attr_name_expr|
18
- owner <<
19
- "def #{temp_method_name}(value)" <<
20
- " _write_attribute(#{attr_name_expr}, value)" <<
21
- "end"
18
+ owner.define_cached_method("#{name}=", as: temp_method_name, namespace: :active_record) do |batch|
19
+ batch <<
20
+ "def #{temp_method_name}(value)" <<
21
+ " _write_attribute(#{attr_name_expr}, value)" <<
22
+ "end"
23
+ end
22
24
  end
23
25
  end
24
26
  end
@@ -42,11 +44,6 @@ module ActiveRecord
42
44
 
43
45
  alias :attribute= :_write_attribute
44
46
  private :attribute=
45
-
46
- private
47
- def write_attribute_without_type_cast(attr_name, value)
48
- @attributes.write_cast_value(attr_name, value)
49
- end
50
47
  end
51
48
  end
52
49
  end
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
 
24
24
  RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
25
25
 
26
- class GeneratedAttributeMethods < Module #:nodoc:
26
+ class GeneratedAttributeMethods < Module # :nodoc:
27
27
  include Mutex_m
28
28
  end
29
29
 
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
  end
40
40
 
41
41
  module ClassMethods
42
- def inherited(child_class) #:nodoc:
42
+ def inherited(child_class) # :nodoc:
43
43
  child_class.initialize_generated_modules
44
44
  super
45
45
  end
@@ -267,9 +267,8 @@ module ActiveRecord
267
267
 
268
268
  # Returns an <tt>#inspect</tt>-like string for the value of the
269
269
  # attribute +attr_name+. String attributes are truncated up to 50
270
- # characters, Date and Time attributes are returned in the
271
- # <tt>:db</tt> format. Other attributes return the value of
272
- # <tt>#inspect</tt> without modification.
270
+ # characters. Other attributes return the value of <tt>#inspect</tt>
271
+ # without modification.
273
272
  #
274
273
  # person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
275
274
  #
@@ -277,7 +276,7 @@ module ActiveRecord
277
276
  # # => "\"David Heinemeier Hansson David Heinemeier Hansson ...\""
278
277
  #
279
278
  # person.attribute_for_inspect(:created_at)
280
- # # => "\"2012-10-22 00:15:07\""
279
+ # # => "\"2012-10-22 00:15:07.000000000 +0000\""
281
280
  #
282
281
  # person.attribute_for_inspect(:tag_ids)
283
282
  # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
@@ -385,25 +384,25 @@ module ActiveRecord
385
384
  end
386
385
 
387
386
  def attributes_with_values(attribute_names)
388
- attribute_names.index_with do |name|
389
- _read_attribute(name)
390
- end
387
+ attribute_names.index_with { |name| @attributes[name] }
391
388
  end
392
389
 
393
- # Filters the primary keys and readonly attributes from the attribute names.
390
+ # Filters the primary keys, readonly attributes and virtual columns from the attribute names.
394
391
  def attributes_for_update(attribute_names)
395
392
  attribute_names &= self.class.column_names
396
393
  attribute_names.delete_if do |name|
397
- self.class.readonly_attribute?(name)
394
+ self.class.readonly_attribute?(name) ||
395
+ column_for_attribute(name).virtual?
398
396
  end
399
397
  end
400
398
 
401
- # Filters out the primary keys, from the attribute names, when the primary
399
+ # Filters out the virtual columns and also primary keys, from the attribute names, when the primary
402
400
  # key is to be generated (e.g. the id attribute has no value).
403
401
  def attributes_for_create(attribute_names)
404
402
  attribute_names &= self.class.column_names
405
403
  attribute_names.delete_if do |name|
406
- pk_attribute?(name) && id.nil?
404
+ (pk_attribute?(name) && id.nil?) ||
405
+ column_for_attribute(name).virtual?
407
406
  end
408
407
  end
409
408
 
@@ -414,7 +413,7 @@ module ActiveRecord
414
413
  inspected_value = if value.is_a?(String) && value.length > 50
415
414
  "#{value[0, 50]}...".inspect
416
415
  elsif value.is_a?(Date) || value.is_a?(Time)
417
- %("#{value.to_s(:inspect)}")
416
+ %("#{value.to_fs(:inspect)}")
418
417
  else
419
418
  value.inspect
420
419
  end
@@ -12,9 +12,6 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ClassMethods
15
- ##
16
- # :call-seq: attribute(name, cast_type = nil, **options)
17
- #
18
15
  # Defines an attribute with a type on this model. It will override the
19
16
  # type of existing attributes if needed. This allows control over how
20
17
  # values are converted to and from SQL when assigned to a model. It also
@@ -208,14 +205,31 @@ module ActiveRecord
208
205
  # tracking is performed. The methods +changed?+ and +changed_in_place?+
209
206
  # will be called from ActiveModel::Dirty. See the documentation for those
210
207
  # methods in ActiveModel::Type::Value for more details.
211
- def attribute(name, cast_type = nil, **options, &block)
208
+ def attribute(name, cast_type = nil, default: NO_DEFAULT_PROVIDED, **options)
212
209
  name = name.to_s
210
+ name = attribute_aliases[name] || name
211
+
213
212
  reload_schema_from_cache
214
213
 
214
+ case cast_type
215
+ when Symbol
216
+ cast_type = Type.lookup(cast_type, **options, adapter: Type.adapter_name_from(self))
217
+ when nil
218
+ if (prev_cast_type, prev_default = attributes_to_define_after_schema_loads[name])
219
+ default = prev_default if default == NO_DEFAULT_PROVIDED
220
+ else
221
+ prev_cast_type = -> subtype { subtype }
222
+ end
223
+
224
+ cast_type = if block_given?
225
+ -> subtype { yield Proc === prev_cast_type ? prev_cast_type[subtype] : prev_cast_type }
226
+ else
227
+ prev_cast_type
228
+ end
229
+ end
230
+
215
231
  self.attributes_to_define_after_schema_loads =
216
- attributes_to_define_after_schema_loads.merge(
217
- name => [cast_type || block, options]
218
- )
232
+ attributes_to_define_after_schema_loads.merge(name => [cast_type, default])
219
233
  end
220
234
 
221
235
  # This is the low level API which sits beneath +attribute+. It only
@@ -248,8 +262,9 @@ module ActiveRecord
248
262
 
249
263
  def load_schema! # :nodoc:
250
264
  super
251
- attributes_to_define_after_schema_loads.each do |name, (type, options)|
252
- define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
265
+ attributes_to_define_after_schema_loads.each do |name, (cast_type, default)|
266
+ cast_type = cast_type[type_for_attribute(name)] if Proc === cast_type
267
+ define_attribute(name, cast_type, default: default)
253
268
  end
254
269
  end
255
270
 
@@ -272,32 +287,6 @@ module ActiveRecord
272
287
  end
273
288
  _default_attributes[name] = default_attribute
274
289
  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
301
290
  end
302
291
  end
303
292
  end
@@ -138,7 +138,7 @@ module ActiveRecord
138
138
  module AutosaveAssociation
139
139
  extend ActiveSupport::Concern
140
140
 
141
- module AssociationBuilderExtension #:nodoc:
141
+ module AssociationBuilderExtension # :nodoc:
142
142
  def self.build(model, reflection)
143
143
  model.send(:add_autosave_association_callbacks, reflection)
144
144
  end
@@ -150,25 +150,10 @@ module ActiveRecord
150
150
 
151
151
  included do
152
152
  Associations::Builder::Association.extensions << AssociationBuilderExtension
153
- mattr_accessor :index_nested_attribute_errors, instance_writer: false, default: false
154
153
  end
155
154
 
156
155
  module ClassMethods # :nodoc:
157
156
  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
-
172
157
  def define_non_cyclic_method(name, &block)
173
158
  return if method_defined?(name, false)
174
159
 
@@ -210,7 +195,7 @@ module ActiveRecord
210
195
  after_create save_method
211
196
  after_update save_method
212
197
  elsif reflection.has_one?
213
- define_method(save_method) { save_has_one_association(reflection) } unless method_defined?(save_method)
198
+ define_non_cyclic_method(save_method) { save_has_one_association(reflection) }
214
199
  # Configures two callbacks instead of a single after_save so that
215
200
  # the model may rely on their execution order relative to its
216
201
  # own callbacks.
@@ -349,7 +334,7 @@ module ActiveRecord
349
334
 
350
335
  unless valid = record.valid?(context)
351
336
  if reflection.options[:autosave]
352
- indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors)
337
+ indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord.index_nested_attribute_errors)
353
338
 
354
339
  record.errors.group_by_attribute.each { |attribute, errors|
355
340
  attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
@@ -419,6 +404,8 @@ module ActiveRecord
419
404
  saved = true
420
405
 
421
406
  if autosave != false && (new_record_before_save || record.new_record?)
407
+ association.set_inverse_instance(record)
408
+
422
409
  if autosave
423
410
  saved = association.insert_record(record, false)
424
411
  elsif !reflection.nested?
@@ -459,12 +446,10 @@ module ActiveRecord
459
446
  elsif autosave != false
460
447
  key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
461
448
 
462
- if (autosave && record.changed_for_autosave?) || record_changed?(reflection, record, key)
449
+ if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, key)
463
450
  unless reflection.through_reflection
464
451
  record[reflection.foreign_key] = key
465
- if inverse_reflection = reflection.inverse_of
466
- record.association(inverse_reflection.name).inversed_from(self)
467
- end
452
+ association.set_inverse_instance(record)
468
453
  end
469
454
 
470
455
  saved = record.save(validate: !autosave)
@@ -476,7 +461,7 @@ module ActiveRecord
476
461
  end
477
462
 
478
463
  # If the record is new or it has changed, returns true.
479
- def record_changed?(reflection, record, key)
464
+ def _record_changed?(reflection, record, key)
480
465
  record.new_record? ||
481
466
  association_foreign_key_changed?(reflection, record, key) ||
482
467
  record.will_save_change_to_attribute?(reflection.foreign_key)
@@ -12,7 +12,7 @@ require "active_record/attributes"
12
12
  require "active_record/type_caster"
13
13
  require "active_record/database_configurations"
14
14
 
15
- module ActiveRecord #:nodoc:
15
+ module ActiveRecord # :nodoc:
16
16
  # = Active Record
17
17
  #
18
18
  # Active Record objects don't specify their attributes directly, but rather infer them from
@@ -137,6 +137,23 @@ module ActiveRecord #:nodoc:
137
137
  # anonymous = User.new(name: "")
138
138
  # anonymous.name? # => false
139
139
  #
140
+ # Query methods will also respect any overwrites of default accessors:
141
+ #
142
+ # class User
143
+ # # Has admin boolean column
144
+ # def admin
145
+ # false
146
+ # end
147
+ # end
148
+ #
149
+ # user.update(admin: true)
150
+ #
151
+ # user.read_attribute(:admin) # => true, gets the column value
152
+ # user[:admin] # => true, also gets the column value
153
+ #
154
+ # user.admin # => false, due to the getter overwrite
155
+ # user.admin? # => false, due to the getter overwrite
156
+ #
140
157
  # == Accessing attributes before they have been typecasted
141
158
  #
142
159
  # Sometimes you want to be able to read the raw attribute data without having the column-determined
@@ -310,6 +327,7 @@ module ActiveRecord #:nodoc:
310
327
  include SecureToken
311
328
  include SignedId
312
329
  include Suppressor
330
+ include Encryption::EncryptableRecord
313
331
  end
314
332
 
315
333
  ActiveSupport.run_load_hooks(:active_record, Base)
@@ -432,7 +432,7 @@ module ActiveRecord
432
432
  define_model_callbacks :save, :create, :update, :destroy
433
433
  end
434
434
 
435
- def destroy #:nodoc:
435
+ def destroy # :nodoc:
436
436
  @_destroy_callback_already_called ||= false
437
437
  return if @_destroy_callback_already_called
438
438
  @_destroy_callback_already_called = true
@@ -444,7 +444,7 @@ module ActiveRecord
444
444
  @_destroy_callback_already_called = false
445
445
  end
446
446
 
447
- def touch(*, **) #:nodoc:
447
+ def touch(*, **) # :nodoc:
448
448
  _run_touch_callbacks { super }
449
449
  end
450
450