activerecord 5.0.7.2 → 6.0.3.4

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 (359) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +708 -2040
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +9 -7
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -22
  8. data/lib/active_record/advisory_lock_base.rb +18 -0
  9. data/lib/active_record/aggregations.rb +249 -247
  10. data/lib/active_record/association_relation.rb +18 -14
  11. data/lib/active_record/associations.rb +1603 -1592
  12. data/lib/active_record/associations/alias_tracker.rb +24 -34
  13. data/lib/active_record/associations/association.rb +114 -55
  14. data/lib/active_record/associations/association_scope.rb +94 -94
  15. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  16. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  17. data/lib/active_record/associations/builder/association.rb +18 -25
  18. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  19. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  20. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +41 -62
  21. data/lib/active_record/associations/builder/has_many.rb +4 -0
  22. data/lib/active_record/associations/builder/has_one.rb +37 -1
  23. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  24. data/lib/active_record/associations/collection_association.rb +86 -254
  25. data/lib/active_record/associations/collection_proxy.rb +158 -122
  26. data/lib/active_record/associations/foreign_association.rb +9 -0
  27. data/lib/active_record/associations/has_many_association.rb +23 -30
  28. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  29. data/lib/active_record/associations/has_one_association.rb +59 -54
  30. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  31. data/lib/active_record/associations/join_dependency.rb +143 -176
  32. data/lib/active_record/associations/join_dependency/join_association.rb +38 -87
  33. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  34. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  35. data/lib/active_record/associations/preloader.rb +90 -103
  36. data/lib/active_record/associations/preloader/association.rb +86 -100
  37. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  38. data/lib/active_record/associations/singular_association.rb +12 -45
  39. data/lib/active_record/associations/through_association.rb +26 -14
  40. data/lib/active_record/attribute_assignment.rb +54 -61
  41. data/lib/active_record/attribute_decorators.rb +38 -17
  42. data/lib/active_record/attribute_methods.rb +66 -106
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -8
  44. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  45. data/lib/active_record/attribute_methods/primary_key.rb +85 -92
  46. data/lib/active_record/attribute_methods/query.rb +4 -3
  47. data/lib/active_record/attribute_methods/read.rb +20 -49
  48. data/lib/active_record/attribute_methods/serialization.rb +29 -7
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -66
  50. data/lib/active_record/attribute_methods/write.rb +34 -33
  51. data/lib/active_record/attributes.rb +38 -25
  52. data/lib/active_record/autosave_association.rb +54 -35
  53. data/lib/active_record/base.rb +27 -24
  54. data/lib/active_record/callbacks.rb +64 -35
  55. data/lib/active_record/coders/json.rb +2 -0
  56. data/lib/active_record/coders/yaml_column.rb +11 -12
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +552 -323
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +215 -94
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -35
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -28
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +228 -147
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +400 -213
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -79
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -202
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +396 -562
  70. data/lib/active_record/connection_adapters/column.rb +41 -13
  71. data/lib/active_record/connection_adapters/connection_specification.rb +172 -139
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  73. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +137 -49
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +48 -30
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -31
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -54
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  101. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -31
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +8 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +20 -26
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +378 -308
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +383 -275
  118. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  120. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  121. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  122. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  123. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  124. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  127. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +259 -266
  128. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  129. data/lib/active_record/connection_handling.rb +143 -40
  130. data/lib/active_record/core.rb +201 -163
  131. data/lib/active_record/counter_cache.rb +60 -28
  132. data/lib/active_record/database_configurations.rb +233 -0
  133. data/lib/active_record/database_configurations/database_config.rb +37 -0
  134. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  135. data/lib/active_record/database_configurations/url_config.rb +78 -0
  136. data/lib/active_record/define_callbacks.rb +22 -0
  137. data/lib/active_record/dynamic_matchers.rb +87 -87
  138. data/lib/active_record/enum.rb +60 -23
  139. data/lib/active_record/errors.rb +114 -18
  140. data/lib/active_record/explain.rb +4 -4
  141. data/lib/active_record/explain_registry.rb +3 -1
  142. data/lib/active_record/explain_subscriber.rb +9 -4
  143. data/lib/active_record/fixture_set/file.rb +13 -8
  144. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  145. data/lib/active_record/fixture_set/render_context.rb +17 -0
  146. data/lib/active_record/fixture_set/table_row.rb +152 -0
  147. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  148. data/lib/active_record/fixtures.rb +194 -504
  149. data/lib/active_record/gem_version.rb +5 -3
  150. data/lib/active_record/inheritance.rb +150 -99
  151. data/lib/active_record/insert_all.rb +179 -0
  152. data/lib/active_record/integration.rb +116 -25
  153. data/lib/active_record/internal_metadata.rb +16 -19
  154. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  155. data/lib/active_record/locking/optimistic.rb +77 -87
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +48 -29
  158. data/lib/active_record/middleware/database_selector.rb +74 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +369 -302
  162. data/lib/active_record/migration/command_recorder.rb +134 -100
  163. data/lib/active_record/migration/compatibility.rb +174 -56
  164. data/lib/active_record/migration/join_table.rb +8 -7
  165. data/lib/active_record/model_schema.rb +131 -127
  166. data/lib/active_record/nested_attributes.rb +213 -202
  167. data/lib/active_record/no_touching.rb +12 -3
  168. data/lib/active_record/null_relation.rb +12 -34
  169. data/lib/active_record/persistence.rb +446 -77
  170. data/lib/active_record/query_cache.rb +13 -12
  171. data/lib/active_record/querying.rb +37 -24
  172. data/lib/active_record/railtie.rb +128 -36
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +312 -177
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +214 -252
  179. data/lib/active_record/relation.rb +440 -318
  180. data/lib/active_record/relation/batches.rb +98 -52
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  182. data/lib/active_record/relation/calculations.rb +212 -173
  183. data/lib/active_record/relation/delegation.rb +72 -69
  184. data/lib/active_record/relation/finder_methods.rb +207 -247
  185. data/lib/active_record/relation/from_clause.rb +6 -8
  186. data/lib/active_record/relation/merger.rb +78 -62
  187. data/lib/active_record/relation/predicate_builder.rb +83 -105
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  195. data/lib/active_record/relation/query_attribute.rb +33 -2
  196. data/lib/active_record/relation/query_methods.rb +476 -334
  197. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  198. data/lib/active_record/relation/spawn_methods.rb +8 -8
  199. data/lib/active_record/relation/where_clause.rb +111 -96
  200. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  201. data/lib/active_record/result.rb +69 -40
  202. data/lib/active_record/runtime_registry.rb +5 -3
  203. data/lib/active_record/sanitization.rb +83 -99
  204. data/lib/active_record/schema.rb +7 -14
  205. data/lib/active_record/schema_dumper.rb +71 -69
  206. data/lib/active_record/schema_migration.rb +16 -6
  207. data/lib/active_record/scoping.rb +20 -20
  208. data/lib/active_record/scoping/default.rb +92 -95
  209. data/lib/active_record/scoping/named.rb +47 -27
  210. data/lib/active_record/secure_token.rb +4 -2
  211. data/lib/active_record/serialization.rb +2 -0
  212. data/lib/active_record/statement_cache.rb +63 -28
  213. data/lib/active_record/store.rb +121 -41
  214. data/lib/active_record/suppressor.rb +6 -3
  215. data/lib/active_record/table_metadata.rb +39 -18
  216. data/lib/active_record/tasks/database_tasks.rb +271 -81
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -91
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +77 -47
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +33 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +225 -0
  222. data/lib/active_record/timestamp.rb +70 -36
  223. data/lib/active_record/touch_later.rb +8 -6
  224. data/lib/active_record/transactions.rb +141 -157
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +23 -18
  227. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  228. data/lib/active_record/type/date.rb +2 -0
  229. data/lib/active_record/type/date_time.rb +2 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  232. data/lib/active_record/type/internal/timezone.rb +2 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +16 -9
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +2 -1
  237. data/lib/active_record/type/type_map.rb +14 -17
  238. data/lib/active_record/type/unsigned_integer.rb +16 -0
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/type_caster/connection.rb +17 -12
  241. data/lib/active_record/type_caster/map.rb +5 -4
  242. data/lib/active_record/validations.rb +7 -5
  243. data/lib/active_record/validations/absence.rb +2 -0
  244. data/lib/active_record/validations/associated.rb +4 -3
  245. data/lib/active_record/validations/length.rb +2 -0
  246. data/lib/active_record/validations/presence.rb +4 -2
  247. data/lib/active_record/validations/uniqueness.rb +29 -42
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +62 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +256 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +203 -0
  317. data/lib/arel/visitors/dot.rb +296 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +156 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +158 -0
  323. data/lib/arel/visitors/oracle12.rb +65 -0
  324. data/lib/arel/visitors/postgresql.rb +109 -0
  325. data/lib/arel/visitors/sqlite.rb +38 -0
  326. data/lib/arel/visitors/to_sql.rb +888 -0
  327. data/lib/arel/visitors/visitor.rb +45 -0
  328. data/lib/arel/visitors/where_sql.rb +22 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  332. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  333. data/lib/rails/generators/active_record/migration.rb +17 -3
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  335. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +9 -30
  338. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +137 -52
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  355. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  356. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  357. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  358. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  359. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  class StatementPool # :nodoc:
@@ -6,7 +8,7 @@ module ActiveRecord
6
8
  DEFAULT_STATEMENT_LIMIT = 1000
7
9
 
8
10
  def initialize(statement_limit = nil)
9
- @cache = Hash.new { |h,pid| h[pid] = {} }
11
+ @cache = Hash.new { |h, pid| h[pid] = {} }
10
12
  @statement_limit = statement_limit || DEFAULT_STATEMENT_LIMIT
11
13
  end
12
14
 
@@ -46,14 +48,13 @@ module ActiveRecord
46
48
  end
47
49
 
48
50
  private
51
+ def cache
52
+ @cache[Process.pid]
53
+ end
49
54
 
50
- def cache
51
- @cache[Process.pid]
52
- end
53
-
54
- def dealloc(stmt)
55
- raise NotImplementedError
56
- end
55
+ def dealloc(stmt)
56
+ raise NotImplementedError
57
+ end
57
58
  end
58
59
  end
59
60
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionHandling
3
- RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
5
+ RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
4
6
  DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
5
7
 
6
8
  # Establishes the connection to the database. Accepts a hash as input where
@@ -44,44 +46,140 @@ module ActiveRecord
44
46
  #
45
47
  # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
46
48
  # may be returned on an error.
47
- def establish_connection(spec = nil)
48
- raise RuntimeError, "Anonymous class is not allowed." unless name
49
+ def establish_connection(config_or_env = nil)
50
+ config_hash = resolve_config_for_connection(config_or_env)
51
+ connection_handler.establish_connection(config_hash)
52
+ end
49
53
 
50
- spec ||= DEFAULT_ENV.call.to_sym
51
- resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
52
- # TODO: uses name on establish_connection, for backwards compatibility
53
- spec = resolver.spec(spec, self == Base ? "primary" : name)
54
+ # Connects a model to the databases specified. The +database+ keyword
55
+ # takes a hash consisting of a +role+ and a +database_key+.
56
+ #
57
+ # This will create a connection handler for switching between connections,
58
+ # look up the config hash using the +database_key+ and finally
59
+ # establishes a connection to that config.
60
+ #
61
+ # class AnimalsModel < ApplicationRecord
62
+ # self.abstract_class = true
63
+ #
64
+ # connects_to database: { writing: :primary, reading: :primary_replica }
65
+ # end
66
+ #
67
+ # Returns an array of established connections.
68
+ def connects_to(database: {})
69
+ connections = []
54
70
 
55
- unless respond_to?(spec.adapter_method)
56
- raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
71
+ database.each do |role, database_key|
72
+ config_hash = resolve_config_for_connection(database_key)
73
+ handler = lookup_connection_handler(role.to_sym)
74
+
75
+ connections << handler.establish_connection(config_hash)
57
76
  end
58
77
 
59
- remove_connection(spec.name)
60
- self.connection_specification_name = spec.name
61
- connection_handler.establish_connection spec
78
+ connections
62
79
  end
63
80
 
64
- class MergeAndResolveDefaultUrlConfig # :nodoc:
65
- def initialize(raw_configurations)
66
- @raw_config = raw_configurations.dup
67
- @env = DEFAULT_ENV.call.to_s
68
- end
81
+ # Connects to a database or role (ex writing, reading, or another
82
+ # custom role) for the duration of the block.
83
+ #
84
+ # If a role is passed, Active Record will look up the connection
85
+ # based on the requested role:
86
+ #
87
+ # ActiveRecord::Base.connected_to(role: :writing) do
88
+ # Dog.create! # creates dog using dog writing connection
89
+ # end
90
+ #
91
+ # ActiveRecord::Base.connected_to(role: :reading) do
92
+ # Dog.create! # throws exception because we're on a replica
93
+ # end
94
+ #
95
+ # ActiveRecord::Base.connected_to(role: :unknown_role) do
96
+ # # raises exception due to non-existent role
97
+ # end
98
+ #
99
+ # The `database` kwarg is deprecated in 6.1 and will be removed in 6.2
100
+ #
101
+ # It is not recommended for use as it re-establishes a connection every
102
+ # time it is called.
103
+ def connected_to(database: nil, role: nil, prevent_writes: false, &blk)
104
+ if database && role
105
+ raise ArgumentError, "connected_to can only accept a `database` or a `role` argument, but not both arguments."
106
+ elsif database
107
+ if database.is_a?(Hash)
108
+ role, database = database.first
109
+ role = role.to_sym
110
+ end
111
+
112
+ config_hash = resolve_config_for_connection(database)
113
+ handler = lookup_connection_handler(role)
69
114
 
70
- # Returns fully resolved connection hashes.
71
- # Merges connection information from `ENV['DATABASE_URL']` if available.
72
- def resolve
73
- ConnectionAdapters::ConnectionSpecification::Resolver.new(config).resolve_all
115
+ handler.establish_connection(config_hash)
116
+
117
+ with_handler(role, &blk)
118
+ elsif role
119
+ prevent_writes = true if role == reading_role
120
+
121
+ with_handler(role.to_sym) do
122
+ connection_handler.while_preventing_writes(prevent_writes, &blk)
123
+ end
124
+ else
125
+ raise ArgumentError, "must provide a `database` or a `role`."
74
126
  end
127
+ end
75
128
 
76
- private
77
- def config
78
- @raw_config.dup.tap do |cfg|
79
- if url = ENV['DATABASE_URL']
80
- cfg[@env] ||= {}
81
- cfg[@env]["url"] ||= url
82
- end
83
- end
129
+ # Returns true if role is the current connected role.
130
+ #
131
+ # ActiveRecord::Base.connected_to(role: :writing) do
132
+ # ActiveRecord::Base.connected_to?(role: :writing) #=> true
133
+ # ActiveRecord::Base.connected_to?(role: :reading) #=> false
134
+ # end
135
+ def connected_to?(role:)
136
+ current_role == role.to_sym
137
+ end
138
+
139
+ # Returns the symbol representing the current connected role.
140
+ #
141
+ # ActiveRecord::Base.connected_to(role: :writing) do
142
+ # ActiveRecord::Base.current_role #=> :writing
143
+ # end
144
+ #
145
+ # ActiveRecord::Base.connected_to(role: :reading) do
146
+ # ActiveRecord::Base.current_role #=> :reading
147
+ # end
148
+ def current_role
149
+ connection_handlers.key(connection_handler)
150
+ end
151
+
152
+ def lookup_connection_handler(handler_key) # :nodoc:
153
+ handler_key ||= ActiveRecord::Base.writing_role
154
+ connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
155
+ end
156
+
157
+ def with_handler(handler_key, &blk) # :nodoc:
158
+ handler = lookup_connection_handler(handler_key)
159
+ swap_connection_handler(handler, &blk)
160
+ end
161
+
162
+ def resolve_config_for_connection(config_or_env) # :nodoc:
163
+ raise "Anonymous class is not allowed." unless name
164
+
165
+ config_or_env ||= DEFAULT_ENV.call.to_sym
166
+ pool_name = primary_class? ? "primary" : name
167
+ self.connection_specification_name = pool_name
168
+
169
+ resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
170
+ config_hash = resolver.resolve(config_or_env, pool_name).symbolize_keys
171
+ config_hash[:name] = pool_name
172
+
173
+ config_hash
174
+ end
175
+
176
+ # Clears the query cache for all connections associated with the current thread.
177
+ def clear_query_caches_for_current_thread
178
+ ActiveRecord::Base.connection_handlers.each_value do |handler|
179
+ handler.connection_pool_list.each do |pool|
180
+ pool.connection.clear_query_cache if pool.active_connection?
84
181
  end
182
+ end
85
183
  end
86
184
 
87
185
  # Returns the connection currently associated with the class. This can
@@ -93,8 +191,7 @@ module ActiveRecord
93
191
 
94
192
  attr_writer :connection_specification_name
95
193
 
96
- # Return the specification id from this class otherwise look it up
97
- # in the parent.
194
+ # Return the specification name from the current class or its parent.
98
195
  def connection_specification_name
99
196
  if !defined?(@connection_specification_name) || @connection_specification_name.nil?
100
197
  return self == Base ? "primary" : superclass.connection_specification_name
@@ -102,12 +199,8 @@ module ActiveRecord
102
199
  @connection_specification_name
103
200
  end
104
201
 
105
- def connection_id
106
- ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id
107
- end
108
-
109
- def connection_id=(connection_id)
110
- ActiveRecord::RuntimeRegistry.connection_id = connection_id
202
+ def primary_class? # :nodoc:
203
+ self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
111
204
  end
112
205
 
113
206
  # Returns the configuration of the associated connection as a hash:
@@ -121,7 +214,7 @@ module ActiveRecord
121
214
  end
122
215
 
123
216
  def connection_pool
124
- connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished
217
+ connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished)
125
218
  end
126
219
 
127
220
  def retrieve_connection
@@ -135,7 +228,7 @@ module ActiveRecord
135
228
 
136
229
  def remove_connection(name = nil)
137
230
  name ||= @connection_specification_name if defined?(@connection_specification_name)
138
- # if removing a connection that have a pool, we reset the
231
+ # if removing a connection that has a pool, we reset the
139
232
  # connection_specification_name so it will use the parent
140
233
  # pool.
141
234
  if connection_handler.retrieve_connection_pool(name)
@@ -150,6 +243,16 @@ module ActiveRecord
150
243
  end
151
244
 
152
245
  delegate :clear_active_connections!, :clear_reloadable_connections!,
153
- :clear_all_connections!, :to => :connection_handler
246
+ :clear_all_connections!, :flush_idle_connections!, to: :connection_handler
247
+
248
+ private
249
+ def swap_connection_handler(handler, &blk) # :nodoc:
250
+ old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
251
+ return_value = yield
252
+ return_value.load if return_value.is_a? ActiveRecord::Relation
253
+ return_value
254
+ ensure
255
+ ActiveRecord::Base.connection_handler = old_handler
256
+ end
154
257
  end
155
258
  end
@@ -1,7 +1,9 @@
1
- require 'thread'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
- require 'active_support/core_ext/object/duplicable'
4
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+ require "active_support/core_ext/string/filters"
5
+ require "active_support/parameter_filter"
6
+ require "concurrent/map"
5
7
 
6
8
  module ActiveRecord
7
9
  module Core
@@ -16,9 +18,16 @@ module ActiveRecord
16
18
  # retrieved on both a class and instance level by calling +logger+.
17
19
  mattr_accessor :logger, instance_writer: false
18
20
 
21
+ ##
22
+ # :singleton-method:
23
+ #
24
+ # Specifies if the methods calling database queries should be logged below
25
+ # their relevant queries. Defaults to false.
26
+ mattr_accessor :verbose_query_logs, instance_writer: false, default: false
27
+
19
28
  ##
20
29
  # Contains the database configuration - as is typically stored in config/database.yml -
21
- # as a Hash.
30
+ # as an ActiveRecord::DatabaseConfigurations object.
22
31
  #
23
32
  # For example, the following database.yml...
24
33
  #
@@ -32,22 +41,18 @@ module ActiveRecord
32
41
  #
33
42
  # ...would result in ActiveRecord::Base.configurations to look like this:
34
43
  #
35
- # {
36
- # 'development' => {
37
- # 'adapter' => 'sqlite3',
38
- # 'database' => 'db/development.sqlite3'
39
- # },
40
- # 'production' => {
41
- # 'adapter' => 'sqlite3',
42
- # 'database' => 'db/production.sqlite3'
43
- # }
44
- # }
44
+ # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
45
+ # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46
+ # @spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>,
47
+ # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48
+ # @spec_name="primary", @config={"adapter"=>"mysql2", "database"=>"db/production.sqlite3"}>
49
+ # ]>
45
50
  def self.configurations=(config)
46
- @@configurations = ActiveRecord::ConnectionHandling::MergeAndResolveDefaultUrlConfig.new(config).resolve
51
+ @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
47
52
  end
48
53
  self.configurations = {}
49
54
 
50
- # Returns fully resolved configurations hash
55
+ # Returns fully resolved ActiveRecord::DatabaseConfigurations object
51
56
  def self.configurations
52
57
  @@configurations
53
58
  end
@@ -56,8 +61,7 @@ module ActiveRecord
56
61
  # :singleton-method:
57
62
  # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
58
63
  # dates and times from the database. This is set to :utc by default.
59
- mattr_accessor :default_timezone, instance_writer: false
60
- self.default_timezone = :utc
64
+ mattr_accessor :default_timezone, instance_writer: false, default: :utc
61
65
 
62
66
  ##
63
67
  # :singleton-method:
@@ -67,31 +71,35 @@ module ActiveRecord
67
71
  # ActiveRecord::Schema file which can be loaded into any database that
68
72
  # supports migrations. Use :ruby if you want to have different database
69
73
  # adapters for, e.g., your development and test environments.
70
- mattr_accessor :schema_format, instance_writer: false
71
- self.schema_format = :ruby
74
+ mattr_accessor :schema_format, instance_writer: false, default: :ruby
72
75
 
73
76
  ##
74
77
  # :singleton-method:
75
- # Specifies if an error should be raised on query limit or order being
78
+ # Specifies if an error should be raised if the query has an order being
76
79
  # ignored when doing batch queries. Useful in applications where the
77
- # limit or scope being ignored is error-worthy, rather than a warning.
78
- mattr_accessor :error_on_ignored_order_or_limit, instance_writer: false
79
- self.error_on_ignored_order_or_limit = false
80
+ # scope being ignored is error-worthy, rather than a warning.
81
+ mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
82
+
83
+ # :singleton-method:
84
+ # Specify the behavior for unsafe raw query methods. Values are as follows
85
+ # deprecated - Warnings are logged when unsafe raw SQL is passed to
86
+ # query methods.
87
+ # disabled - Unsafe raw SQL passed to query methods results in
88
+ # UnknownAttributeReference exception.
89
+ mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
80
90
 
81
91
  ##
82
92
  # :singleton-method:
83
93
  # Specify whether or not to use timestamps for migration versions
84
- mattr_accessor :timestamped_migrations, instance_writer: false
85
- self.timestamped_migrations = true
94
+ mattr_accessor :timestamped_migrations, instance_writer: false, default: true
86
95
 
87
96
  ##
88
97
  # :singleton-method:
89
98
  # Specify whether schema dump should happen at the end of the
90
- # db:migrate rake task. This is true by default, which is useful for the
99
+ # db:migrate rails command. This is true by default, which is useful for the
91
100
  # development environment. This should ideally be false in the production
92
101
  # environment where dumping schema is rarely needed.
93
- mattr_accessor :dump_schema_after_migration, instance_writer: false
94
- self.dump_schema_after_migration = true
102
+ mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
95
103
 
96
104
  ##
97
105
  # :singleton-method:
@@ -100,8 +108,7 @@ module ActiveRecord
100
108
  # schema_search_path are dumped. Use :all to dump all schemas regardless
101
109
  # of schema_search_path, or a string of comma separated schemas for a
102
110
  # custom list.
103
- mattr_accessor :dump_schemas, instance_writer: false
104
- self.dump_schemas = :schema_search_path
111
+ mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
105
112
 
106
113
  ##
107
114
  # :singleton-method:
@@ -110,33 +117,35 @@ module ActiveRecord
110
117
  # be used to identify queries which load thousands of records and
111
118
  # potentially cause memory bloat.
112
119
  mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
113
- self.warn_on_records_fetched_greater_than = nil
114
120
 
115
121
  mattr_accessor :maintain_test_schema, instance_accessor: false
116
122
 
117
123
  mattr_accessor :belongs_to_required_by_default, instance_accessor: false
118
124
 
125
+ mattr_accessor :connection_handlers, instance_accessor: false, default: {}
126
+
127
+ mattr_accessor :writing_role, instance_accessor: false, default: :writing
128
+
129
+ mattr_accessor :reading_role, instance_accessor: false, default: :reading
130
+
119
131
  class_attribute :default_connection_handler, instance_writer: false
120
132
 
133
+ self.filter_attributes = []
134
+
121
135
  def self.connection_handler
122
- ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
136
+ Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
123
137
  end
124
138
 
125
139
  def self.connection_handler=(handler)
126
- ActiveRecord::RuntimeRegistry.connection_handler = handler
140
+ Thread.current.thread_variable_set("ar_connection_handler", handler)
127
141
  end
128
142
 
129
143
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
130
144
  end
131
145
 
132
146
  module ClassMethods
133
- def allocate
134
- define_attribute_methods
135
- super
136
- end
137
-
138
147
  def initialize_find_by_cache # :nodoc:
139
- @find_by_statement_cache = { true => {}.extend(Mutex_m), false => {}.extend(Mutex_m) }
148
+ @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
140
149
  end
141
150
 
142
151
  def inherited(child_class) # :nodoc:
@@ -151,41 +160,33 @@ module ActiveRecord
151
160
  return super if block_given? ||
152
161
  primary_key.nil? ||
153
162
  scope_attributes? ||
154
- columns_hash.include?(inheritance_column) ||
155
- ids.first.kind_of?(Array)
156
-
157
- id = ids.first
158
- if ActiveRecord::Base === id
159
- id = id.id
160
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
161
- You are passing an instance of ActiveRecord::Base to `find`.
162
- Please pass the id of the object by calling `.id`.
163
- MSG
164
- end
163
+ columns_hash.key?(inheritance_column) && !base_class?
164
+
165
+ id = ids.first
166
+
167
+ return super if StatementCache.unsupported_value?(id)
165
168
 
166
169
  key = primary_key
167
170
 
168
171
  statement = cached_find_by_statement(key) { |params|
169
172
  where(key => params.bind).limit(1)
170
173
  }
171
- record = statement.execute([id], self, connection).first
174
+
175
+ record = statement.execute([id], connection)&.first
172
176
  unless record
173
- raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
174
- name, primary_key, id)
177
+ raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
175
178
  end
176
179
  record
177
- rescue RangeError
178
- raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
179
- name, primary_key)
180
180
  end
181
181
 
182
182
  def find_by(*args) # :nodoc:
183
- return super if scope_attributes? || reflect_on_all_aggregations.any?
183
+ return super if scope_attributes? || reflect_on_all_aggregations.any? ||
184
+ columns_hash.key?(inheritance_column) && !base_class?
184
185
 
185
186
  hash = args.first
186
187
 
187
188
  return super if !(Hash === hash) || hash.values.any? { |v|
188
- v.nil? || Array === v || Hash === v || Relation === v || Base === v
189
+ StatementCache.unsupported_value?(v)
189
190
  }
190
191
 
191
192
  # We can't cache Post.find_by(author: david) ...yet
@@ -200,32 +201,44 @@ module ActiveRecord
200
201
  where(wheres).limit(1)
201
202
  }
202
203
  begin
203
- statement.execute(hash.values, self, connection).first
204
+ statement.execute(hash.values, connection)&.first
204
205
  rescue TypeError
205
206
  raise ActiveRecord::StatementInvalid
206
- rescue RangeError
207
- nil
208
207
  end
209
208
  end
210
209
 
211
210
  def find_by!(*args) # :nodoc:
212
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
211
+ find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
213
212
  end
214
213
 
215
214
  def initialize_generated_modules # :nodoc:
216
215
  generated_association_methods
217
216
  end
218
217
 
219
- def generated_association_methods
218
+ def generated_association_methods # :nodoc:
220
219
  @generated_association_methods ||= begin
221
220
  mod = const_set(:GeneratedAssociationMethods, Module.new)
221
+ private_constant :GeneratedAssociationMethods
222
222
  include mod
223
+
223
224
  mod
224
225
  end
225
226
  end
226
227
 
228
+ # Returns columns which shouldn't be exposed while calling +#inspect+.
229
+ def filter_attributes
230
+ if defined?(@filter_attributes)
231
+ @filter_attributes
232
+ else
233
+ superclass.filter_attributes
234
+ end
235
+ end
236
+
237
+ # Specifies columns which shouldn't be exposed while calling +#inspect+.
238
+ attr_writer :filter_attributes
239
+
227
240
  # Returns a string like 'Post(id:integer, title:string, body:text)'
228
- def inspect
241
+ def inspect # :nodoc:
229
242
  if self == Base
230
243
  super
231
244
  elsif abstract_class?
@@ -233,39 +246,30 @@ module ActiveRecord
233
246
  elsif !connected?
234
247
  "#{super} (call '#{super}.connection' to establish a connection)"
235
248
  elsif table_exists?
236
- attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
249
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
237
250
  "#{super}(#{attr_list})"
238
251
  else
239
252
  "#{super}(Table doesn't exist)"
240
253
  end
241
254
  end
242
255
 
243
- # Overwrite the default class equality method to provide support for association proxies.
244
- def ===(object)
256
+ # Overwrite the default class equality method to provide support for decorated models.
257
+ def ===(object) # :nodoc:
245
258
  object.is_a?(self)
246
259
  end
247
260
 
248
261
  # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
249
262
  #
250
263
  # class Post < ActiveRecord::Base
251
- # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
264
+ # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
252
265
  # end
253
266
  def arel_table # :nodoc:
254
267
  @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
255
268
  end
256
269
 
257
- # Returns the Arel engine.
258
- def arel_engine # :nodoc:
259
- @arel_engine ||=
260
- if Base == self || connection_handler.retrieve_connection_pool(connection_specification_name)
261
- self
262
- else
263
- superclass.arel_engine
264
- end
265
- end
266
-
267
270
  def arel_attribute(name, table = arel_table) # :nodoc:
268
- name = attribute_alias(name) if attribute_alias?(name)
271
+ name = name.to_s
272
+ name = attribute_aliases[name] || name
269
273
  table[name]
270
274
  end
271
275
 
@@ -277,28 +281,30 @@ module ActiveRecord
277
281
  TypeCaster::Map.new(self)
278
282
  end
279
283
 
280
- private
281
-
282
- def cached_find_by_statement(key, &block) # :nodoc:
283
- cache = @find_by_statement_cache[connection.prepared_statements]
284
- cache[key] || cache.synchronize {
285
- cache[key] ||= StatementCache.create(connection, &block)
286
- }
284
+ def _internal? # :nodoc:
285
+ false
287
286
  end
288
287
 
289
- def relation # :nodoc:
290
- relation = Relation.create(self, arel_table, predicate_builder)
288
+ private
289
+ def cached_find_by_statement(key, &block)
290
+ cache = @find_by_statement_cache[connection.prepared_statements]
291
+ cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
292
+ end
291
293
 
292
- if finder_needs_type_condition? && !ignore_default_scope?
293
- relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
294
- else
295
- relation
294
+ def relation
295
+ relation = Relation.create(self)
296
+
297
+ if finder_needs_type_condition? && !ignore_default_scope?
298
+ relation.where!(type_condition)
299
+ relation.create_with!(inheritance_column.to_s => sti_name)
300
+ else
301
+ relation
302
+ end
296
303
  end
297
- end
298
304
 
299
- def table_metadata # :nodoc:
300
- TableMetadata.new(self, arel_table)
301
- end
305
+ def table_metadata
306
+ TableMetadata.new(self, arel_table)
307
+ end
302
308
  end
303
309
 
304
310
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -310,7 +316,7 @@ module ActiveRecord
310
316
  # # Instantiates a single new object
311
317
  # User.new(first_name: 'Jamie')
312
318
  def initialize(attributes = nil)
313
- self.class.define_attribute_methods
319
+ @new_record = true
314
320
  @attributes = self.class._default_attributes.deep_dup
315
321
 
316
322
  init_internals
@@ -336,15 +342,21 @@ module ActiveRecord
336
342
  # post = Post.allocate
337
343
  # post.init_with(coder)
338
344
  # post.title # => 'hello world'
339
- def init_with(coder)
345
+ def init_with(coder, &block)
340
346
  coder = LegacyYamlAdapter.convert(self.class, coder)
341
- @attributes = coder['attributes']
342
-
343
- init_internals
347
+ attributes = self.class.yaml_encoder.decode(coder)
348
+ init_with_attributes(attributes, coder["new_record"], &block)
349
+ end
344
350
 
345
- @new_record = coder['new_record']
351
+ ##
352
+ # Initialize an empty model object from +attributes+.
353
+ # +attributes+ should be an attributes object, and unlike the
354
+ # `initialize` method, no assignment calls are made per attribute.
355
+ def init_with_attributes(attributes, new_record = false) # :nodoc:
356
+ @new_record = new_record
357
+ @attributes = attributes
346
358
 
347
- self.class.define_attribute_methods
359
+ init_internals
348
360
 
349
361
  yield self if block_given?
350
362
 
@@ -383,12 +395,14 @@ module ActiveRecord
383
395
  ##
384
396
  def initialize_dup(other) # :nodoc:
385
397
  @attributes = @attributes.deep_dup
386
- @attributes.reset(self.class.primary_key)
398
+ @attributes.reset(@primary_key)
387
399
 
388
400
  _run_initialize_callbacks
389
401
 
390
- @new_record = true
391
- @destroyed = false
402
+ @new_record = true
403
+ @destroyed = false
404
+ @_start_transaction_state = nil
405
+ @transaction_state = nil
392
406
 
393
407
  super
394
408
  end
@@ -406,11 +420,9 @@ module ActiveRecord
406
420
  # Post.new.encode_with(coder)
407
421
  # coder # => {"attributes" => {"id" => nil, ... }}
408
422
  def encode_with(coder)
409
- # FIXME: Remove this when we better serialize attributes
410
- coder['raw_attributes'] = attributes_before_type_cast
411
- coder['attributes'] = @attributes
412
- coder['new_record'] = new_record?
413
- coder['active_record_yaml_version'] = 1
423
+ self.class.yaml_encoder.encode(@attributes, coder)
424
+ coder["new_record"] = new_record?
425
+ coder["active_record_yaml_version"] = 2
414
426
  end
415
427
 
416
428
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
@@ -434,7 +446,7 @@ module ActiveRecord
434
446
  # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
435
447
  def hash
436
448
  if id
437
- id.hash
449
+ self.class.hash ^ id.hash
438
450
  else
439
451
  super
440
452
  end
@@ -450,18 +462,27 @@ module ActiveRecord
450
462
 
451
463
  # Returns +true+ if the attributes hash has been frozen.
452
464
  def frozen?
465
+ sync_with_transaction_state if @transaction_state&.finalized?
453
466
  @attributes.frozen?
454
467
  end
455
468
 
456
469
  # Allows sort on objects
457
470
  def <=>(other_object)
458
471
  if other_object.is_a?(self.class)
459
- self.to_key <=> other_object.to_key
472
+ to_key <=> other_object.to_key
460
473
  else
461
474
  super
462
475
  end
463
476
  end
464
477
 
478
+ def present? # :nodoc:
479
+ true
480
+ end
481
+
482
+ def blank? # :nodoc:
483
+ false
484
+ end
485
+
465
486
  # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
466
487
  # attributes will be marked as read only since they cannot be saved.
467
488
  def readonly?
@@ -482,14 +503,22 @@ module ActiveRecord
482
503
  # We check defined?(@attributes) not to issue warnings if the object is
483
504
  # allocated but not initialized.
484
505
  inspection = if defined?(@attributes) && @attributes
485
- self.class.column_names.collect { |name|
486
- if has_attribute?(name)
487
- "#{name}: #{attribute_for_inspect(name)}"
488
- end
489
- }.compact.join(", ")
490
- else
491
- "not initialized"
492
- end
506
+ self.class.attribute_names.collect do |name|
507
+ if has_attribute?(name)
508
+ attr = _read_attribute(name)
509
+ value = if attr.nil?
510
+ attr.inspect
511
+ else
512
+ attr = format_for_inspect(attr)
513
+ inspection_filter.filter_param(name, attr)
514
+ end
515
+ "#{name}: #{value}"
516
+ end
517
+ end.compact.join(", ")
518
+ else
519
+ "not initialized"
520
+ end
521
+
493
522
  "#<#{self.class} #{inspection}>"
494
523
  end
495
524
 
@@ -499,65 +528,74 @@ module ActiveRecord
499
528
  return super if custom_inspect_method_defined?
500
529
  pp.object_address_group(self) do
501
530
  if defined?(@attributes) && @attributes
502
- column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
503
- pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
504
- column_value = read_attribute(column_name)
505
- pp.breakable ' '
531
+ attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
532
+ pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
533
+ pp.breakable " "
506
534
  pp.group(1) do
507
- pp.text column_name
508
- pp.text ':'
535
+ pp.text attr_name
536
+ pp.text ":"
509
537
  pp.breakable
510
- pp.pp column_value
538
+ value = _read_attribute(attr_name)
539
+ value = inspection_filter.filter_param(attr_name, value) unless value.nil?
540
+ pp.pp value
511
541
  end
512
542
  end
513
543
  else
514
- pp.breakable ' '
515
- pp.text 'not initialized'
544
+ pp.breakable " "
545
+ pp.text "not initialized"
516
546
  end
517
547
  end
518
548
  end
519
549
 
520
550
  # Returns a hash of the given methods with their names as keys and returned values as values.
521
551
  def slice(*methods)
522
- Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
552
+ Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
523
553
  end
524
554
 
525
555
  private
556
+ # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
557
+ # the array, and then rescues from the possible +NoMethodError+. If those elements are
558
+ # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
559
+ # which significantly impacts upon performance.
560
+ #
561
+ # So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
562
+ #
563
+ # See also https://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
564
+ def to_ary
565
+ nil
566
+ end
526
567
 
527
- # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
528
- # of the array, and then rescues from the possible NoMethodError. If those elements are
529
- # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
530
- # which significantly impacts upon performance.
531
- #
532
- # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
533
- #
534
- # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
535
- def to_ary # :nodoc:
536
- nil
537
- end
568
+ def init_internals
569
+ @primary_key = self.class.primary_key
570
+ @readonly = false
571
+ @destroyed = false
572
+ @marked_for_destruction = false
573
+ @destroyed_by_association = nil
574
+ @_start_transaction_state = nil
575
+ @transaction_state = nil
538
576
 
539
- def init_internals
540
- @readonly = false
541
- @destroyed = false
542
- @marked_for_destruction = false
543
- @destroyed_by_association = nil
544
- @new_record = true
545
- @txn = nil
546
- @_start_transaction_state = {}
547
- @transaction_state = nil
548
- end
577
+ self.class.define_attribute_methods
578
+ end
549
579
 
550
- def initialize_internals_callback
551
- end
580
+ def initialize_internals_callback
581
+ end
552
582
 
553
- def thaw
554
- if frozen?
555
- @attributes = @attributes.dup
583
+ def custom_inspect_method_defined?
584
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
556
585
  end
557
- end
558
586
 
559
- def custom_inspect_method_defined?
560
- self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
561
- end
587
+ class InspectionMask < DelegateClass(::String)
588
+ def pretty_print(pp)
589
+ pp.text __getobj__
590
+ end
591
+ end
592
+ private_constant :InspectionMask
593
+
594
+ def inspection_filter
595
+ @inspection_filter ||= begin
596
+ mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
597
+ ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
598
+ end
599
+ end
562
600
  end
563
601
  end