activerecord 5.2.8 → 7.0.2

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 (364) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1393 -587
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +10 -9
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +122 -47
  10. data/lib/active_record/associations/association_scope.rb +24 -24
  11. data/lib/active_record/associations/belongs_to_association.rb +67 -49
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
  13. data/lib/active_record/associations/builder/association.rb +52 -23
  14. data/lib/active_record/associations/builder/belongs_to.rb +44 -61
  15. data/lib/active_record/associations/builder/collection_association.rb +17 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +10 -3
  18. data/lib/active_record/associations/builder/has_one.rb +35 -3
  19. data/lib/active_record/associations/builder/singular_association.rb +5 -3
  20. data/lib/active_record/associations/collection_association.rb +59 -50
  21. data/lib/active_record/associations/collection_proxy.rb +32 -23
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +27 -14
  25. data/lib/active_record/associations/has_many_through_association.rb +26 -19
  26. data/lib/active_record/associations/has_one_association.rb +52 -37
  27. data/lib/active_record/associations/has_one_through_association.rb +6 -6
  28. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  29. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +97 -62
  31. data/lib/active_record/associations/preloader/association.rb +220 -60
  32. data/lib/active_record/associations/preloader/batch.rb +48 -0
  33. data/lib/active_record/associations/preloader/branch.rb +147 -0
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -40
  35. data/lib/active_record/associations/preloader.rb +44 -105
  36. data/lib/active_record/associations/singular_association.rb +9 -17
  37. data/lib/active_record/associations/through_association.rb +4 -4
  38. data/lib/active_record/associations.rb +207 -66
  39. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  40. data/lib/active_record/attribute_assignment.rb +17 -19
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
  42. data/lib/active_record/attribute_methods/dirty.rb +141 -47
  43. data/lib/active_record/attribute_methods/primary_key.rb +22 -27
  44. data/lib/active_record/attribute_methods/query.rb +6 -10
  45. data/lib/active_record/attribute_methods/read.rb +15 -55
  46. data/lib/active_record/attribute_methods/serialization.rb +77 -18
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
  48. data/lib/active_record/attribute_methods/write.rb +18 -37
  49. data/lib/active_record/attribute_methods.rb +90 -153
  50. data/lib/active_record/attributes.rb +38 -12
  51. data/lib/active_record/autosave_association.rb +50 -50
  52. data/lib/active_record/base.rb +23 -18
  53. data/lib/active_record/callbacks.rb +159 -44
  54. data/lib/active_record/coders/yaml_column.rb +12 -3
  55. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
  63. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
  71. data/lib/active_record/connection_adapters/column.rb +33 -11
  72. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  73. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  74. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  75. data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
  76. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  77. data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
  78. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  80. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
  81. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
  82. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  83. data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
  84. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  85. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +53 -28
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
  95. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
  116. data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
  122. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
  123. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  124. data/lib/active_record/connection_adapters.rb +53 -0
  125. data/lib/active_record/connection_handling.rb +292 -38
  126. data/lib/active_record/core.rb +385 -158
  127. data/lib/active_record/counter_cache.rb +8 -30
  128. data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
  129. data/lib/active_record/database_configurations/database_config.rb +83 -0
  130. data/lib/active_record/database_configurations/hash_config.rb +154 -0
  131. data/lib/active_record/database_configurations/url_config.rb +53 -0
  132. data/lib/active_record/database_configurations.rb +256 -0
  133. data/lib/active_record/delegated_type.rb +250 -0
  134. data/lib/active_record/destroy_association_async_job.rb +36 -0
  135. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  136. data/lib/active_record/dynamic_matchers.rb +4 -5
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +44 -0
  140. data/lib/active_record/encryption/configurable.rb +61 -0
  141. data/lib/active_record/encryption/context.rb +35 -0
  142. data/lib/active_record/encryption/contexts.rb +72 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +155 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +42 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_serializer.rb +90 -0
  159. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  160. data/lib/active_record/encryption/properties.rb +76 -0
  161. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  162. data/lib/active_record/encryption/scheme.rb +99 -0
  163. data/lib/active_record/encryption.rb +55 -0
  164. data/lib/active_record/enum.rb +130 -51
  165. data/lib/active_record/errors.rb +129 -23
  166. data/lib/active_record/explain.rb +10 -6
  167. data/lib/active_record/explain_registry.rb +11 -6
  168. data/lib/active_record/explain_subscriber.rb +1 -1
  169. data/lib/active_record/fixture_set/file.rb +22 -15
  170. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  171. data/lib/active_record/fixture_set/render_context.rb +17 -0
  172. data/lib/active_record/fixture_set/table_row.rb +187 -0
  173. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  174. data/lib/active_record/fixtures.rb +206 -490
  175. data/lib/active_record/future_result.rb +139 -0
  176. data/lib/active_record/gem_version.rb +3 -3
  177. data/lib/active_record/inheritance.rb +104 -37
  178. data/lib/active_record/insert_all.rb +278 -0
  179. data/lib/active_record/integration.rb +69 -18
  180. data/lib/active_record/internal_metadata.rb +24 -9
  181. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  182. data/lib/active_record/locking/optimistic.rb +41 -26
  183. data/lib/active_record/locking/pessimistic.rb +18 -8
  184. data/lib/active_record/log_subscriber.rb +46 -35
  185. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  186. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  187. data/lib/active_record/middleware/database_selector.rb +82 -0
  188. data/lib/active_record/middleware/shard_selector.rb +60 -0
  189. data/lib/active_record/migration/command_recorder.rb +96 -44
  190. data/lib/active_record/migration/compatibility.rb +246 -64
  191. data/lib/active_record/migration/join_table.rb +1 -2
  192. data/lib/active_record/migration.rb +266 -187
  193. data/lib/active_record/model_schema.rb +165 -52
  194. data/lib/active_record/nested_attributes.rb +17 -19
  195. data/lib/active_record/no_touching.rb +11 -4
  196. data/lib/active_record/null_relation.rb +2 -7
  197. data/lib/active_record/persistence.rb +467 -92
  198. data/lib/active_record/query_cache.rb +21 -4
  199. data/lib/active_record/query_logs.rb +138 -0
  200. data/lib/active_record/querying.rb +51 -24
  201. data/lib/active_record/railtie.rb +224 -57
  202. data/lib/active_record/railties/console_sandbox.rb +2 -4
  203. data/lib/active_record/railties/controller_runtime.rb +31 -36
  204. data/lib/active_record/railties/databases.rake +369 -101
  205. data/lib/active_record/readonly_attributes.rb +15 -0
  206. data/lib/active_record/reflection.rb +170 -137
  207. data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
  208. data/lib/active_record/relation/batches.rb +46 -37
  209. data/lib/active_record/relation/calculations.rb +168 -96
  210. data/lib/active_record/relation/delegation.rb +37 -52
  211. data/lib/active_record/relation/finder_methods.rb +79 -58
  212. data/lib/active_record/relation/from_clause.rb +5 -1
  213. data/lib/active_record/relation/merger.rb +50 -51
  214. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  215. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  216. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  217. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  218. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  219. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  220. data/lib/active_record/relation/predicate_builder.rb +58 -46
  221. data/lib/active_record/relation/query_attribute.rb +9 -10
  222. data/lib/active_record/relation/query_methods.rb +685 -208
  223. data/lib/active_record/relation/record_fetch_warning.rb +9 -11
  224. data/lib/active_record/relation/spawn_methods.rb +10 -10
  225. data/lib/active_record/relation/where_clause.rb +108 -64
  226. data/lib/active_record/relation.rb +515 -151
  227. data/lib/active_record/result.rb +78 -42
  228. data/lib/active_record/runtime_registry.rb +9 -13
  229. data/lib/active_record/sanitization.rb +29 -44
  230. data/lib/active_record/schema.rb +37 -31
  231. data/lib/active_record/schema_dumper.rb +74 -23
  232. data/lib/active_record/schema_migration.rb +7 -9
  233. data/lib/active_record/scoping/default.rb +62 -17
  234. data/lib/active_record/scoping/named.rb +17 -32
  235. data/lib/active_record/scoping.rb +70 -41
  236. data/lib/active_record/secure_token.rb +16 -8
  237. data/lib/active_record/serialization.rb +6 -4
  238. data/lib/active_record/signed_id.rb +116 -0
  239. data/lib/active_record/statement_cache.rb +49 -6
  240. data/lib/active_record/store.rb +88 -9
  241. data/lib/active_record/suppressor.rb +13 -17
  242. data/lib/active_record/table_metadata.rb +42 -43
  243. data/lib/active_record/tasks/database_tasks.rb +352 -94
  244. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  245. data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
  246. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  247. data/lib/active_record/test_databases.rb +24 -0
  248. data/lib/active_record/test_fixtures.rb +287 -0
  249. data/lib/active_record/timestamp.rb +44 -34
  250. data/lib/active_record/touch_later.rb +23 -22
  251. data/lib/active_record/transactions.rb +67 -128
  252. data/lib/active_record/translation.rb +3 -3
  253. data/lib/active_record/type/adapter_specific_registry.rb +34 -19
  254. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  255. data/lib/active_record/type/internal/timezone.rb +2 -2
  256. data/lib/active_record/type/serialized.rb +7 -4
  257. data/lib/active_record/type/time.rb +10 -0
  258. data/lib/active_record/type/type_map.rb +17 -21
  259. data/lib/active_record/type/unsigned_integer.rb +0 -1
  260. data/lib/active_record/type.rb +9 -5
  261. data/lib/active_record/type_caster/connection.rb +15 -15
  262. data/lib/active_record/type_caster/map.rb +8 -8
  263. data/lib/active_record/validations/associated.rb +2 -3
  264. data/lib/active_record/validations/numericality.rb +35 -0
  265. data/lib/active_record/validations/uniqueness.rb +39 -31
  266. data/lib/active_record/validations.rb +4 -3
  267. data/lib/active_record.rb +209 -32
  268. data/lib/arel/alias_predication.rb +9 -0
  269. data/lib/arel/attributes/attribute.rb +33 -0
  270. data/lib/arel/collectors/bind.rb +29 -0
  271. data/lib/arel/collectors/composite.rb +39 -0
  272. data/lib/arel/collectors/plain_string.rb +20 -0
  273. data/lib/arel/collectors/sql_string.rb +27 -0
  274. data/lib/arel/collectors/substitute_binds.rb +35 -0
  275. data/lib/arel/crud.rb +48 -0
  276. data/lib/arel/delete_manager.rb +32 -0
  277. data/lib/arel/errors.rb +9 -0
  278. data/lib/arel/expressions.rb +29 -0
  279. data/lib/arel/factory_methods.rb +49 -0
  280. data/lib/arel/filter_predications.rb +9 -0
  281. data/lib/arel/insert_manager.rb +48 -0
  282. data/lib/arel/math.rb +45 -0
  283. data/lib/arel/nodes/and.rb +32 -0
  284. data/lib/arel/nodes/ascending.rb +23 -0
  285. data/lib/arel/nodes/binary.rb +126 -0
  286. data/lib/arel/nodes/bind_param.rb +44 -0
  287. data/lib/arel/nodes/case.rb +55 -0
  288. data/lib/arel/nodes/casted.rb +62 -0
  289. data/lib/arel/nodes/comment.rb +29 -0
  290. data/lib/arel/nodes/count.rb +12 -0
  291. data/lib/arel/nodes/delete_statement.rb +44 -0
  292. data/lib/arel/nodes/descending.rb +23 -0
  293. data/lib/arel/nodes/equality.rb +15 -0
  294. data/lib/arel/nodes/extract.rb +24 -0
  295. data/lib/arel/nodes/false.rb +16 -0
  296. data/lib/arel/nodes/filter.rb +10 -0
  297. data/lib/arel/nodes/full_outer_join.rb +8 -0
  298. data/lib/arel/nodes/function.rb +45 -0
  299. data/lib/arel/nodes/grouping.rb +11 -0
  300. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  301. data/lib/arel/nodes/in.rb +15 -0
  302. data/lib/arel/nodes/infix_operation.rb +92 -0
  303. data/lib/arel/nodes/inner_join.rb +8 -0
  304. data/lib/arel/nodes/insert_statement.rb +37 -0
  305. data/lib/arel/nodes/join_source.rb +20 -0
  306. data/lib/arel/nodes/matches.rb +18 -0
  307. data/lib/arel/nodes/named_function.rb +23 -0
  308. data/lib/arel/nodes/node.rb +51 -0
  309. data/lib/arel/nodes/node_expression.rb +13 -0
  310. data/lib/arel/nodes/ordering.rb +27 -0
  311. data/lib/arel/nodes/outer_join.rb +8 -0
  312. data/lib/arel/nodes/over.rb +15 -0
  313. data/lib/arel/nodes/regexp.rb +16 -0
  314. data/lib/arel/nodes/right_outer_join.rb +8 -0
  315. data/lib/arel/nodes/select_core.rb +67 -0
  316. data/lib/arel/nodes/select_statement.rb +41 -0
  317. data/lib/arel/nodes/sql_literal.rb +19 -0
  318. data/lib/arel/nodes/string_join.rb +11 -0
  319. data/lib/arel/nodes/table_alias.rb +31 -0
  320. data/lib/arel/nodes/terminal.rb +16 -0
  321. data/lib/arel/nodes/true.rb +16 -0
  322. data/lib/arel/nodes/unary.rb +44 -0
  323. data/lib/arel/nodes/unary_operation.rb +20 -0
  324. data/lib/arel/nodes/unqualified_column.rb +22 -0
  325. data/lib/arel/nodes/update_statement.rb +46 -0
  326. data/lib/arel/nodes/values_list.rb +9 -0
  327. data/lib/arel/nodes/window.rb +126 -0
  328. data/lib/arel/nodes/with.rb +11 -0
  329. data/lib/arel/nodes.rb +71 -0
  330. data/lib/arel/order_predications.rb +13 -0
  331. data/lib/arel/predications.rb +258 -0
  332. data/lib/arel/select_manager.rb +276 -0
  333. data/lib/arel/table.rb +117 -0
  334. data/lib/arel/tree_manager.rb +60 -0
  335. data/lib/arel/update_manager.rb +48 -0
  336. data/lib/arel/visitors/dot.rb +298 -0
  337. data/lib/arel/visitors/mysql.rb +99 -0
  338. data/lib/arel/visitors/postgresql.rb +110 -0
  339. data/lib/arel/visitors/sqlite.rb +38 -0
  340. data/lib/arel/visitors/to_sql.rb +955 -0
  341. data/lib/arel/visitors/visitor.rb +45 -0
  342. data/lib/arel/visitors.rb +13 -0
  343. data/lib/arel/window_predications.rb +9 -0
  344. data/lib/arel.rb +55 -0
  345. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  346. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  347. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  348. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  349. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  350. data/lib/rails/generators/active_record/migration.rb +19 -2
  351. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  352. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  353. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  354. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  355. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  356. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  357. metadata +162 -32
  358. data/lib/active_record/attribute_decorators.rb +0 -90
  359. data/lib/active_record/collection_cache_key.rb +0 -53
  360. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  361. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  362. data/lib/active_record/define_callbacks.rb +0 -22
  363. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  364. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -4,26 +4,26 @@ require "active_model/forbidden_attributes_protection"
4
4
 
5
5
  module ActiveRecord
6
6
  module AttributeAssignment
7
- extend ActiveSupport::Concern
8
7
  include ActiveModel::AttributeAssignment
9
8
 
10
9
  private
11
-
12
10
  def _assign_attributes(attributes)
13
- multi_parameter_attributes = {}
14
- nested_parameter_attributes = {}
11
+ multi_parameter_attributes = nested_parameter_attributes = nil
15
12
 
16
13
  attributes.each do |k, v|
17
- if k.include?("(")
18
- multi_parameter_attributes[k] = attributes.delete(k)
14
+ key = k.to_s
15
+
16
+ if key.include?("(")
17
+ (multi_parameter_attributes ||= {})[key] = v
19
18
  elsif v.is_a?(Hash)
20
- nested_parameter_attributes[k] = attributes.delete(k)
19
+ (nested_parameter_attributes ||= {})[key] = v
20
+ else
21
+ _assign_attribute(key, v)
21
22
  end
22
23
  end
23
- super(attributes)
24
24
 
25
- assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
26
- assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
25
+ assign_nested_parameter_attributes(nested_parameter_attributes) if nested_parameter_attributes
26
+ assign_multiparameter_attributes(multi_parameter_attributes) if multi_parameter_attributes
27
27
  end
28
28
 
29
29
  # Assign any deferred nested attributes after the base attributes have been set.
@@ -46,16 +46,14 @@ module ActiveRecord
46
46
  def execute_callstack_for_multiparameter_attributes(callstack)
47
47
  errors = []
48
48
  callstack.each do |name, values_with_empty_parameters|
49
- begin
50
- if values_with_empty_parameters.each_value.all?(&:nil?)
51
- values = nil
52
- else
53
- values = values_with_empty_parameters
54
- end
55
- send("#{name}=", values)
56
- rescue => ex
57
- errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
49
+ if values_with_empty_parameters.each_value.all?(NilClass)
50
+ values = nil
51
+ else
52
+ values = values_with_empty_parameters
58
53
  end
54
+ send("#{name}=", values)
55
+ rescue => ex
56
+ errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
59
57
  end
60
58
  unless errors.empty?
61
59
  error_descriptions = errors.map(&:message).join(",")
@@ -29,8 +29,8 @@ module ActiveRecord
29
29
  extend ActiveSupport::Concern
30
30
 
31
31
  included do
32
- attribute_method_suffix "_before_type_cast"
33
- attribute_method_suffix "_came_from_user?"
32
+ attribute_method_suffix "_before_type_cast", "_for_database", parameters: false
33
+ attribute_method_suffix "_came_from_user?", parameters: false
34
34
  end
35
35
 
36
36
  # Returns the value of the attribute identified by +attr_name+ before
@@ -46,7 +46,10 @@ module ActiveRecord
46
46
  # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
47
47
  # task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
48
48
  def read_attribute_before_type_cast(attr_name)
49
- @attributes[attr_name.to_s].value_before_type_cast
49
+ name = attr_name.to_s
50
+ name = self.class.attribute_aliases[name] || name
51
+
52
+ attribute_before_type_cast(name)
50
53
  end
51
54
 
52
55
  # Returns a hash of attributes before typecasting and deserialization.
@@ -63,15 +66,23 @@ module ActiveRecord
63
66
  @attributes.values_before_type_cast
64
67
  end
65
68
 
69
+ # Returns a hash of attributes for assignment to the database.
70
+ def attributes_for_database
71
+ @attributes.values_for_database
72
+ end
73
+
66
74
  private
75
+ # Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
76
+ def attribute_before_type_cast(attr_name)
77
+ @attributes[attr_name].value_before_type_cast
78
+ end
67
79
 
68
- # Handle *_before_type_cast for method_missing.
69
- def attribute_before_type_cast(attribute_name)
70
- read_attribute_before_type_cast(attribute_name)
80
+ def attribute_for_database(attr_name)
81
+ @attributes[attr_name].value_for_database
71
82
  end
72
83
 
73
- def attribute_came_from_user?(attribute_name)
74
- @attributes[attribute_name].came_from_user?
84
+ def attribute_came_from_user?(attr_name)
85
+ @attributes[attr_name].came_from_user?
75
86
  end
76
87
  end
77
88
  end
@@ -14,33 +14,59 @@ module ActiveRecord
14
14
  raise "You cannot include Dirty after Timestamp"
15
15
  end
16
16
 
17
- class_attribute :partial_writes, instance_writer: false, default: true
17
+ class_attribute :partial_updates, instance_writer: false, default: true
18
+ class_attribute :partial_inserts, instance_writer: false, default: true
18
19
 
19
20
  # Attribute methods for "changed in last call to save?"
20
- attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
21
- attribute_method_prefix("saved_change_to_")
22
- attribute_method_suffix("_before_last_save")
21
+ attribute_method_affix(prefix: "saved_change_to_", suffix: "?", parameters: "**options")
22
+ attribute_method_prefix("saved_change_to_", parameters: false)
23
+ attribute_method_suffix("_before_last_save", parameters: false)
23
24
 
24
25
  # Attribute methods for "will change if I call save?"
25
- attribute_method_affix(prefix: "will_save_change_to_", suffix: "?")
26
- attribute_method_suffix("_change_to_be_saved", "_in_database")
26
+ attribute_method_affix(prefix: "will_save_change_to_", suffix: "?", parameters: "**options")
27
+ attribute_method_suffix("_change_to_be_saved", "_in_database", parameters: false)
28
+ end
29
+
30
+ module ClassMethods
31
+ def partial_writes
32
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
33
+ ActiveRecord::Base.partial_writes is deprecated and will be removed in Rails 7.1.
34
+ Use `partial_updates` and `partial_inserts` instead.
35
+ MSG
36
+ partial_updates && partial_inserts
37
+ end
38
+
39
+ def partial_writes?
40
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
41
+ `ActiveRecord::Base.partial_writes?` is deprecated and will be removed in Rails 7.1.
42
+ Use `partial_updates?` and `partial_inserts?` instead.
43
+ MSG
44
+ partial_updates? && partial_inserts?
45
+ end
46
+
47
+ def partial_writes=(value)
48
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
49
+ `ActiveRecord::Base.partial_writes=` is deprecated and will be removed in Rails 7.1.
50
+ Use `partial_updates=` and `partial_inserts=` instead.
51
+ MSG
52
+ self.partial_updates = self.partial_inserts = value
53
+ end
27
54
  end
28
55
 
29
56
  # <tt>reload</tt> the record and clears changed attributes.
30
57
  def reload(*)
31
58
  super.tap do
32
- @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
33
59
  @mutations_before_last_save = nil
34
- @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
35
60
  @mutations_from_database = nil
36
61
  end
37
62
  end
38
63
 
39
- # Did this attribute change when we last saved? This method can be invoked
40
- # as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>.
41
- # Behaves similarly to +attribute_changed?+. This method is useful in
42
- # after callbacks to determine if the call to save changed a certain
43
- # attribute.
64
+ # Did this attribute change when we last saved?
65
+ #
66
+ # This method is useful in after callbacks to determine if an attribute
67
+ # was changed during the save that triggered the callbacks to run. It can
68
+ # be invoked as +saved_change_to_name?+ instead of
69
+ # <tt>saved_change_to_attribute?("name")</tt>.
44
70
  #
45
71
  # ==== Options
46
72
  #
@@ -50,28 +76,29 @@ module ActiveRecord
50
76
  # +to+ When passed, this method will return false unless the value was
51
77
  # changed to the given value
52
78
  def saved_change_to_attribute?(attr_name, **options)
53
- mutations_before_last_save.changed?(attr_name, **options)
79
+ mutations_before_last_save.changed?(attr_name.to_s, **options)
54
80
  end
55
81
 
56
82
  # Returns the change to an attribute during the last save. If the
57
83
  # attribute was changed, the result will be an array containing the
58
84
  # original value and the saved value.
59
85
  #
60
- # Behaves similarly to +attribute_change+. This method is useful in after
61
- # callbacks, to see the change in an attribute that just occurred
62
- #
63
- # This method can be invoked as +saved_change_to_name+ in instead of
64
- # <tt>saved_change_to_attribute("name")</tt>
86
+ # This method is useful in after callbacks, to see the change in an
87
+ # attribute during the save that triggered the callbacks to run. It can be
88
+ # invoked as +saved_change_to_name+ instead of
89
+ # <tt>saved_change_to_attribute("name")</tt>.
65
90
  def saved_change_to_attribute(attr_name)
66
- mutations_before_last_save.change_to_attribute(attr_name)
91
+ mutations_before_last_save.change_to_attribute(attr_name.to_s)
67
92
  end
68
93
 
69
94
  # Returns the original value of an attribute before the last save.
70
- # Behaves similarly to +attribute_was+. This method is useful in after
71
- # callbacks to get the original value of an attribute before the save that
72
- # just occurred
95
+ #
96
+ # This method is useful in after callbacks to get the original value of an
97
+ # attribute before the save that triggered the callbacks to run. It can be
98
+ # invoked as +name_before_last_save+ instead of
99
+ # <tt>attribute_before_last_save("name")</tt>.
73
100
  def attribute_before_last_save(attr_name)
74
- mutations_before_last_save.original_value(attr_name)
101
+ mutations_before_last_save.original_value(attr_name.to_s)
75
102
  end
76
103
 
77
104
  # Did the last call to +save+ have any changes to change?
@@ -84,66 +111,133 @@ module ActiveRecord
84
111
  mutations_before_last_save.changes
85
112
  end
86
113
 
87
- # Alias for +attribute_changed?+
114
+ # Will this attribute change the next time we save?
115
+ #
116
+ # This method is useful in validations and before callbacks to determine
117
+ # if the next call to +save+ will change a particular attribute. It can be
118
+ # invoked as +will_save_change_to_name?+ instead of
119
+ # <tt>will_save_change_to_attribute?("name")</tt>.
120
+ #
121
+ # ==== Options
122
+ #
123
+ # +from+ When passed, this method will return false unless the original
124
+ # value is equal to the given option
125
+ #
126
+ # +to+ When passed, this method will return false unless the value will be
127
+ # changed to the given value
88
128
  def will_save_change_to_attribute?(attr_name, **options)
89
- mutations_from_database.changed?(attr_name, **options)
129
+ mutations_from_database.changed?(attr_name.to_s, **options)
90
130
  end
91
131
 
92
- # Alias for +attribute_change+
132
+ # Returns the change to an attribute that will be persisted during the
133
+ # next save.
134
+ #
135
+ # This method is useful in validations and before callbacks, to see the
136
+ # change to an attribute that will occur when the record is saved. It can
137
+ # be invoked as +name_change_to_be_saved+ instead of
138
+ # <tt>attribute_change_to_be_saved("name")</tt>.
139
+ #
140
+ # If the attribute will change, the result will be an array containing the
141
+ # original value and the new value about to be saved.
93
142
  def attribute_change_to_be_saved(attr_name)
94
- mutations_from_database.change_to_attribute(attr_name)
143
+ mutations_from_database.change_to_attribute(attr_name.to_s)
95
144
  end
96
145
 
97
- # Alias for +attribute_was+
146
+ # Returns the value of an attribute in the database, as opposed to the
147
+ # in-memory value that will be persisted the next time the record is
148
+ # saved.
149
+ #
150
+ # This method is useful in validations and before callbacks, to see the
151
+ # original value of an attribute prior to any changes about to be
152
+ # saved. It can be invoked as +name_in_database+ instead of
153
+ # <tt>attribute_in_database("name")</tt>.
98
154
  def attribute_in_database(attr_name)
99
- mutations_from_database.original_value(attr_name)
155
+ mutations_from_database.original_value(attr_name.to_s)
100
156
  end
101
157
 
102
- # Alias for +changed?+
158
+ # Will the next call to +save+ have any changes to persist?
103
159
  def has_changes_to_save?
104
160
  mutations_from_database.any_changes?
105
161
  end
106
162
 
107
- # Alias for +changes+
163
+ # Returns a hash containing all the changes that will be persisted during
164
+ # the next save.
108
165
  def changes_to_save
109
166
  mutations_from_database.changes
110
167
  end
111
168
 
112
- # Alias for +changed+
169
+ # Returns an array of the names of any attributes that will change when
170
+ # the record is next saved.
113
171
  def changed_attribute_names_to_save
114
172
  mutations_from_database.changed_attribute_names
115
173
  end
116
174
 
117
- # Alias for +changed_attributes+
175
+ # Returns a hash of the attributes that will change when the record is
176
+ # next saved.
177
+ #
178
+ # The hash keys are the attribute names, and the hash values are the
179
+ # original attribute values in the database (as opposed to the in-memory
180
+ # values about to be saved).
118
181
  def attributes_in_database
119
182
  mutations_from_database.changed_values
120
183
  end
121
184
 
122
185
  private
123
- def write_attribute_without_type_cast(attr_name, value)
124
- name = attr_name.to_s
125
- if self.class.attribute_alias?(name)
126
- name = self.class.attribute_alias(name)
186
+ def _touch_row(attribute_names, time)
187
+ @_touch_attr_names = Set.new(attribute_names)
188
+
189
+ affected_rows = super
190
+
191
+ if @_skip_dirty_tracking ||= false
192
+ clear_attribute_changes(@_touch_attr_names)
193
+ return affected_rows
127
194
  end
128
- result = super(name, value)
129
- clear_attribute_change(name)
130
- result
195
+
196
+ changes = {}
197
+ @attributes.keys.each do |attr_name|
198
+ next if @_touch_attr_names.include?(attr_name)
199
+
200
+ if attribute_changed?(attr_name)
201
+ changes[attr_name] = _read_attribute(attr_name)
202
+ _write_attribute(attr_name, attribute_was(attr_name))
203
+ clear_attribute_change(attr_name)
204
+ end
205
+ end
206
+
207
+ changes_applied
208
+ changes.each { |attr_name, value| _write_attribute(attr_name, value) }
209
+
210
+ affected_rows
211
+ ensure
212
+ @_touch_attr_names, @_skip_dirty_tracking = nil, nil
131
213
  end
132
214
 
133
- def _update_record(*)
134
- affected_rows = partial_writes? ? super(keys_for_partial_write) : super
215
+ def _update_record(attribute_names = attribute_names_for_partial_updates)
216
+ affected_rows = super
135
217
  changes_applied
136
218
  affected_rows
137
219
  end
138
220
 
139
- def _create_record(*)
140
- id = partial_writes? ? super(keys_for_partial_write) : super
221
+ def _create_record(attribute_names = attribute_names_for_partial_inserts)
222
+ id = super
141
223
  changes_applied
142
224
  id
143
225
  end
144
226
 
145
- def keys_for_partial_write
146
- changed_attribute_names_to_save & self.class.column_names
227
+ def attribute_names_for_partial_updates
228
+ partial_updates? ? changed_attribute_names_to_save : attribute_names
229
+ end
230
+
231
+ def attribute_names_for_partial_inserts
232
+ if partial_inserts?
233
+ changed_attribute_names_to_save
234
+ else
235
+ attribute_names.reject do |attr_name|
236
+ if column_for_attribute(attr_name).default_function
237
+ !attribute_changed?(attr_name)
238
+ end
239
+ end
240
+ end
147
241
  end
148
242
  end
149
243
  end
@@ -14,51 +14,47 @@ module ActiveRecord
14
14
  [key] if key
15
15
  end
16
16
 
17
- # Returns the primary key value.
17
+ # Returns the primary key column's value.
18
18
  def id
19
- sync_with_transaction_state
20
- primary_key = self.class.primary_key
21
- _read_attribute(primary_key) if primary_key
19
+ _read_attribute(@primary_key)
22
20
  end
23
21
 
24
- # Sets the primary key value.
22
+ # Sets the primary key column's value.
25
23
  def id=(value)
26
- sync_with_transaction_state
27
- primary_key = self.class.primary_key
28
- _write_attribute(primary_key, value) if primary_key
24
+ _write_attribute(@primary_key, value)
29
25
  end
30
26
 
31
- # Queries the primary key value.
27
+ # Queries the primary key column's value.
32
28
  def id?
33
- sync_with_transaction_state
34
- query_attribute(self.class.primary_key)
29
+ query_attribute(@primary_key)
35
30
  end
36
31
 
37
- # Returns the primary key value before type cast.
32
+ # Returns the primary key column's value before type cast.
38
33
  def id_before_type_cast
39
- sync_with_transaction_state
40
- read_attribute_before_type_cast(self.class.primary_key)
34
+ attribute_before_type_cast(@primary_key)
41
35
  end
42
36
 
43
- # Returns the primary key previous value.
37
+ # Returns the primary key column's previous value.
44
38
  def id_was
45
- sync_with_transaction_state
46
- attribute_was(self.class.primary_key)
39
+ attribute_was(@primary_key)
47
40
  end
48
41
 
42
+ # Returns the primary key column's value from the database.
49
43
  def id_in_database
50
- sync_with_transaction_state
51
- attribute_in_database(self.class.primary_key)
44
+ attribute_in_database(@primary_key)
52
45
  end
53
46
 
54
- private
47
+ def id_for_database # :nodoc:
48
+ @attributes[@primary_key].value_for_database
49
+ end
55
50
 
51
+ private
56
52
  def attribute_method?(attr_name)
57
53
  attr_name == "id" || super
58
54
  end
59
55
 
60
56
  module ClassMethods
61
- ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
57
+ ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database id_for_database).to_set
62
58
 
63
59
  def instance_method_already_implemented?(method_name)
64
60
  super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
@@ -82,15 +78,15 @@ module ActiveRecord
82
78
  @quoted_primary_key ||= connection.quote_column_name(primary_key)
83
79
  end
84
80
 
85
- def reset_primary_key #:nodoc:
86
- if self == base_class
81
+ def reset_primary_key # :nodoc:
82
+ if base_class?
87
83
  self.primary_key = get_primary_key(base_class.name)
88
84
  else
89
85
  self.primary_key = base_class.primary_key
90
86
  end
91
87
  end
92
88
 
93
- def get_primary_key(base_name) #:nodoc:
89
+ def get_primary_key(base_name) # :nodoc:
94
90
  if base_name && primary_key_prefix_type == :table_name
95
91
  base_name.foreign_key(false)
96
92
  elsif base_name && primary_key_prefix_type == :table_name_with_underscore
@@ -121,17 +117,16 @@ module ActiveRecord
121
117
  #
122
118
  # Project.primary_key # => "foo_id"
123
119
  def primary_key=(value)
124
- @primary_key = value && value.to_s
120
+ @primary_key = value && -value.to_s
125
121
  @quoted_primary_key = nil
126
122
  @attributes_builder = nil
127
123
  end
128
124
 
129
125
  private
130
-
131
126
  def suppress_composite_primary_key(pk)
132
127
  return pk unless pk.is_a?(Array)
133
128
 
134
- warn <<-WARNING.strip_heredoc
129
+ warn <<~WARNING
135
130
  WARNING: Active Record does not support composite primary key.
136
131
 
137
132
  #{table_name} has composite primary key. Composite primary key is ignored.
@@ -6,19 +6,18 @@ 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
17
17
  when false, nil then false
18
18
  else
19
- column = self.class.columns_hash[attr_name]
20
- if column.nil?
21
- if Numeric === value || value !~ /[^0-9]/
19
+ if !type_for_attribute(attr_name) { false }
20
+ if Numeric === value || !value.match?(/[^0-9]/)
22
21
  !value.to_i.zero?
23
22
  else
24
23
  return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
@@ -32,11 +31,8 @@ module ActiveRecord
32
31
  end
33
32
  end
34
33
 
35
- private
36
- # Handle *? for method_missing.
37
- def attribute?(attribute_name)
38
- query_attribute(attribute_name)
39
- end
34
+ alias :attribute? :query_attribute
35
+ private :attribute?
40
36
  end
41
37
  end
42
38
  end
@@ -7,43 +7,16 @@ module ActiveRecord
7
7
 
8
8
  module ClassMethods # :nodoc:
9
9
  private
10
-
11
- # We want to generate the methods via module_eval rather than
12
- # define_method, because define_method is slower on dispatch.
13
- # Evaluating many similar methods may use more memory as the instruction
14
- # sequences are duplicated and cached (in MRI). define_method may
15
- # be slower on dispatch, but if you're careful about the closure
16
- # created, then define_method will consume much less memory.
17
- #
18
- # But sometimes the database might return columns with
19
- # characters that are not allowed in normal method names (like
20
- # 'my_column(omg)'. So to work around this we first define with
21
- # the __temp__ identifier, and then use alias method to rename
22
- # it to what we want.
23
- #
24
- # We are also defining a constant to hold the frozen string of
25
- # the attribute name. Using a constant means that we do not have
26
- # to allocate an object on each call to the attribute method.
27
- # Making it frozen means that it doesn't get duped when used to
28
- # key the @attributes in read_attribute.
29
- def define_method_attribute(name)
30
- safe_name = name.unpack("h*".freeze).first
31
- temp_method = "__temp__#{safe_name}"
32
-
33
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
34
- sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
35
-
36
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
37
- def #{temp_method}
38
- #{sync_with_transaction_state}
39
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
40
- _read_attribute(name) { |n| missing_attribute(n, caller) }
10
+ def define_method_attribute(name, owner:)
11
+ ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
12
+ owner, name
13
+ ) do |temp_method_name, attr_name_expr|
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"
41
19
  end
42
- STR
43
-
44
- generated_attribute_methods.module_eval do
45
- alias_method name, temp_method
46
- undef_method temp_method
47
20
  end
48
21
  end
49
22
  end
@@ -52,30 +25,17 @@ module ActiveRecord
52
25
  # it has been typecast (for example, "2004-12-12" in a date column is cast
53
26
  # to a date object, like Date.new(2004, 12, 12)).
54
27
  def read_attribute(attr_name, &block)
55
- name = if self.class.attribute_alias?(attr_name)
56
- self.class.attribute_alias(attr_name).to_s
57
- else
58
- attr_name.to_s
59
- end
28
+ name = attr_name.to_s
29
+ name = self.class.attribute_aliases[name] || name
60
30
 
61
- primary_key = self.class.primary_key
62
- name = primary_key if name == "id".freeze && primary_key
63
- sync_with_transaction_state if name == primary_key
64
- _read_attribute(name, &block)
31
+ name = @primary_key if name == "id" && @primary_key
32
+ @attributes.fetch_value(name, &block)
65
33
  end
66
34
 
67
35
  # This method exists to avoid the expensive primary_key check internally, without
68
36
  # breaking compatibility with the read_attribute API
69
- if defined?(JRUBY_VERSION)
70
- # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
71
- # https://github.com/jruby/jruby/pull/2562
72
- def _read_attribute(attr_name, &block) # :nodoc:
73
- @attributes.fetch_value(attr_name.to_s, &block)
74
- end
75
- else
76
- def _read_attribute(attr_name) # :nodoc:
77
- @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
78
- end
37
+ def _read_attribute(attr_name, &block) # :nodoc:
38
+ @attributes.fetch_value(attr_name, &block)
79
39
  end
80
40
 
81
41
  alias :attribute :_read_attribute