activerecord 6.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (340) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1013 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +195 -0
  8. data/lib/active_record/aggregations.rb +285 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1865 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +332 -0
  13. data/lib/active_record/associations/association_scope.rb +166 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +124 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +36 -0
  16. data/lib/active_record/associations/builder/association.rb +136 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +130 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +72 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +114 -0
  20. data/lib/active_record/associations/builder/has_many.rb +19 -0
  21. data/lib/active_record/associations/builder/has_one.rb +64 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +44 -0
  23. data/lib/active_record/associations/collection_association.rb +498 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1128 -0
  25. data/lib/active_record/associations/foreign_association.rb +20 -0
  26. data/lib/active_record/associations/has_many_association.rb +136 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +220 -0
  28. data/lib/active_record/associations/has_one_association.rb +118 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +258 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +80 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +201 -0
  35. data/lib/active_record/associations/preloader/association.rb +133 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +116 -0
  37. data/lib/active_record/associations/singular_association.rb +59 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +85 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +420 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +81 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +221 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +136 -0
  45. data/lib/active_record/attribute_methods/query.rb +41 -0
  46. data/lib/active_record/attribute_methods/read.rb +47 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +61 -0
  50. data/lib/active_record/attributes.rb +279 -0
  51. data/lib/active_record/autosave_association.rb +508 -0
  52. data/lib/active_record/base.rb +328 -0
  53. data/lib/active_record/callbacks.rb +339 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1165 -0
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +85 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +512 -0
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +154 -0
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +251 -0
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +713 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1475 -0
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +761 -0
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +821 -0
  69. data/lib/active_record/connection_adapters/column.rb +95 -0
  70. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +146 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +949 -0
  117. data/lib/active_record/connection_adapters/schema_cache.rb +141 -0
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +557 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +267 -0
  129. data/lib/active_record/core.rb +599 -0
  130. data/lib/active_record/counter_cache.rb +193 -0
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +122 -0
  137. data/lib/active_record/enum.rb +274 -0
  138. data/lib/active_record/errors.rb +388 -0
  139. data/lib/active_record/explain.rb +50 -0
  140. data/lib/active_record/explain_registry.rb +32 -0
  141. data/lib/active_record/explain_subscriber.rb +34 -0
  142. data/lib/active_record/fixture_set/file.rb +82 -0
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +738 -0
  148. data/lib/active_record/gem_version.rb +17 -0
  149. data/lib/active_record/inheritance.rb +293 -0
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +207 -0
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  154. data/lib/active_record/locale/en.yml +48 -0
  155. data/lib/active_record/locking/optimistic.rb +197 -0
  156. data/lib/active_record/locking/pessimistic.rb +89 -0
  157. data/lib/active_record/log_subscriber.rb +118 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +1397 -0
  162. data/lib/active_record/migration/command_recorder.rb +284 -0
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +17 -0
  165. data/lib/active_record/model_schema.rb +542 -0
  166. data/lib/active_record/nested_attributes.rb +600 -0
  167. data/lib/active_record/no_touching.rb +65 -0
  168. data/lib/active_record/null_relation.rb +68 -0
  169. data/lib/active_record/persistence.rb +967 -0
  170. data/lib/active_record/query_cache.rb +52 -0
  171. data/lib/active_record/querying.rb +82 -0
  172. data/lib/active_record/railtie.rb +263 -0
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +7 -0
  175. data/lib/active_record/railties/controller_runtime.rb +51 -0
  176. data/lib/active_record/railties/databases.rake +527 -0
  177. data/lib/active_record/readonly_attributes.rb +24 -0
  178. data/lib/active_record/reflection.rb +1042 -0
  179. data/lib/active_record/relation.rb +859 -0
  180. data/lib/active_record/relation/batches.rb +290 -0
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +424 -0
  183. data/lib/active_record/relation/delegation.rb +130 -0
  184. data/lib/active_record/relation/finder_methods.rb +552 -0
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +184 -0
  187. data/lib/active_record/relation/predicate_builder.rb +150 -0
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  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 +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  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 +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +1359 -0
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +77 -0
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +168 -0
  202. data/lib/active_record/runtime_registry.rb +24 -0
  203. data/lib/active_record/sanitization.rb +214 -0
  204. data/lib/active_record/schema.rb +61 -0
  205. data/lib/active_record/schema_dumper.rb +270 -0
  206. data/lib/active_record/schema_migration.rb +60 -0
  207. data/lib/active_record/scoping.rb +106 -0
  208. data/lib/active_record/scoping/default.rb +151 -0
  209. data/lib/active_record/scoping/named.rb +217 -0
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +22 -0
  212. data/lib/active_record/statement_cache.rb +148 -0
  213. data/lib/active_record/store.rb +290 -0
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +506 -0
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +167 -0
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +493 -0
  225. data/lib/active_record/translation.rb +24 -0
  226. data/lib/active_record/type.rb +78 -0
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +9 -0
  229. data/lib/active_record/type/date_time.rb +9 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +71 -0
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +21 -0
  237. data/lib/active_record/type/type_map.rb +62 -0
  238. data/lib/active_record/type/unsigned_integer.rb +17 -0
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +94 -0
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +60 -0
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +68 -0
  247. data/lib/active_record/validations/uniqueness.rb +226 -0
  248. data/lib/active_record/version.rb +10 -0
  249. data/lib/arel.rb +51 -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 +257 -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 +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -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 +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +19 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +48 -0
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +75 -0
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  337. data/lib/rails/generators/active_record/model/model_generator.rb +49 -0
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  340. metadata +415 -0
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # ActiveRecord::Suppressor prevents the receiver from being saved during
5
+ # a given block.
6
+ #
7
+ # For example, here's a pattern of creating notifications when new comments
8
+ # are posted. (The notification may in turn trigger an email, a push
9
+ # notification, or just appear in the UI somewhere):
10
+ #
11
+ # class Comment < ActiveRecord::Base
12
+ # belongs_to :commentable, polymorphic: true
13
+ # after_create -> { Notification.create! comment: self,
14
+ # recipients: commentable.recipients }
15
+ # end
16
+ #
17
+ # That's what you want the bulk of the time. New comment creates a new
18
+ # Notification. But there may well be off cases, like copying a commentable
19
+ # and its comments, where you don't want that. So you'd have a concern
20
+ # something like this:
21
+ #
22
+ # module Copyable
23
+ # def copy_to(destination)
24
+ # Notification.suppress do
25
+ # # Copy logic that creates new comments that we do not want
26
+ # # triggering notifications.
27
+ # end
28
+ # end
29
+ # end
30
+ module Suppressor
31
+ extend ActiveSupport::Concern
32
+
33
+ module ClassMethods
34
+ def suppress(&block)
35
+ previous_state = SuppressorRegistry.suppressed[name]
36
+ SuppressorRegistry.suppressed[name] = true
37
+ yield
38
+ ensure
39
+ SuppressorRegistry.suppressed[name] = previous_state
40
+ end
41
+ end
42
+
43
+ def save(*) # :nodoc:
44
+ SuppressorRegistry.suppressed[self.class.name] ? true : super
45
+ end
46
+
47
+ def save!(*) # :nodoc:
48
+ SuppressorRegistry.suppressed[self.class.name] ? true : super
49
+ end
50
+ end
51
+
52
+ class SuppressorRegistry # :nodoc:
53
+ extend ActiveSupport::PerThreadRegistry
54
+
55
+ attr_reader :suppressed
56
+
57
+ def initialize
58
+ @suppressed = {}
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class TableMetadata # :nodoc:
5
+ delegate :foreign_type, :foreign_key, :join_primary_key, :join_foreign_key, to: :association, prefix: true
6
+
7
+ def initialize(klass, arel_table, association = nil, types = klass)
8
+ @klass = klass
9
+ @types = types
10
+ @arel_table = arel_table
11
+ @association = association
12
+ end
13
+
14
+ def resolve_column_aliases(hash)
15
+ new_hash = hash.dup
16
+ hash.each_key do |key|
17
+ if key.is_a?(Symbol) && new_key = klass.attribute_aliases[key.to_s]
18
+ new_hash[new_key] = new_hash.delete(key)
19
+ end
20
+ end
21
+ new_hash
22
+ end
23
+
24
+ def arel_attribute(column_name)
25
+ if klass
26
+ klass.arel_attribute(column_name, arel_table)
27
+ else
28
+ arel_table[column_name]
29
+ end
30
+ end
31
+
32
+ def type(column_name)
33
+ types.type_for_attribute(column_name)
34
+ end
35
+
36
+ def has_column?(column_name)
37
+ klass && klass.columns_hash.key?(column_name.to_s)
38
+ end
39
+
40
+ def associated_with?(association_name)
41
+ klass && klass._reflect_on_association(association_name)
42
+ end
43
+
44
+ def associated_table(table_name)
45
+ association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.to_s.singularize)
46
+
47
+ if !association && table_name == arel_table.name
48
+ return self
49
+ elsif association && !association.polymorphic?
50
+ association_klass = association.klass
51
+ arel_table = association_klass.arel_table.alias(table_name)
52
+ TableMetadata.new(association_klass, arel_table, association)
53
+ else
54
+ type_caster = TypeCaster::Connection.new(klass, table_name)
55
+ arel_table = Arel::Table.new(table_name, type_caster: type_caster)
56
+ TableMetadata.new(nil, arel_table, association, type_caster)
57
+ end
58
+ end
59
+
60
+ def polymorphic_association?
61
+ association && association.polymorphic?
62
+ end
63
+
64
+ def aggregated_with?(aggregation_name)
65
+ klass && reflect_on_aggregation(aggregation_name)
66
+ end
67
+
68
+ def reflect_on_aggregation(aggregation_name)
69
+ klass.reflect_on_aggregation(aggregation_name)
70
+ end
71
+
72
+ private
73
+ attr_reader :klass, :types, :arel_table, :association
74
+ end
75
+ end
@@ -0,0 +1,506 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/database_configurations"
4
+
5
+ module ActiveRecord
6
+ module Tasks # :nodoc:
7
+ class DatabaseAlreadyExists < StandardError; end # :nodoc:
8
+ class DatabaseNotSupported < StandardError; end # :nodoc:
9
+
10
+ # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
11
+ # logic behind common tasks used to manage database and migrations.
12
+ #
13
+ # The tasks defined here are used with Rails commands provided by Active Record.
14
+ #
15
+ # In order to use DatabaseTasks, a few config values need to be set. All the needed
16
+ # config values are set by Rails already, so it's necessary to do it only if you
17
+ # want to change the defaults or when you want to use Active Record outside of Rails
18
+ # (in such case after configuring the database tasks, you can also use the rake tasks
19
+ # defined in Active Record).
20
+ #
21
+ # The possible config values are:
22
+ #
23
+ # * +env+: current environment (like Rails.env).
24
+ # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
25
+ # * +db_dir+: your +db+ directory.
26
+ # * +fixtures_path+: a path to fixtures directory.
27
+ # * +migrations_paths+: a list of paths to directories with migrations.
28
+ # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
29
+ # * +root+: a path to the root of the application.
30
+ #
31
+ # Example usage of DatabaseTasks outside Rails could look as such:
32
+ #
33
+ # include ActiveRecord::Tasks
34
+ # DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
35
+ # DatabaseTasks.db_dir = 'db'
36
+ # # other settings...
37
+ #
38
+ # DatabaseTasks.create_current('production')
39
+ module DatabaseTasks
40
+ ##
41
+ # :singleton-method:
42
+ # Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:structure:dump
43
+ mattr_accessor :structure_dump_flags, instance_accessor: false
44
+
45
+ ##
46
+ # :singleton-method:
47
+ # Extra flags passed to database CLI tool when calling db:structure:load
48
+ mattr_accessor :structure_load_flags, instance_accessor: false
49
+
50
+ extend self
51
+
52
+ attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
53
+ attr_accessor :database_configuration
54
+
55
+ LOCAL_HOSTS = ["127.0.0.1", "localhost"]
56
+
57
+ def check_protected_environments!
58
+ unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
59
+ current = ActiveRecord::Base.connection.migration_context.current_environment
60
+ stored = ActiveRecord::Base.connection.migration_context.last_stored_environment
61
+
62
+ if ActiveRecord::Base.connection.migration_context.protected_environment?
63
+ raise ActiveRecord::ProtectedEnvironmentError.new(stored)
64
+ end
65
+
66
+ if stored && stored != current
67
+ raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
68
+ end
69
+ end
70
+ rescue ActiveRecord::NoDatabaseError
71
+ end
72
+
73
+ def register_task(pattern, task)
74
+ @tasks ||= {}
75
+ @tasks[pattern] = task
76
+ end
77
+
78
+ register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
79
+ register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
80
+ register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
81
+
82
+ def db_dir
83
+ @db_dir ||= Rails.application.config.paths["db"].first
84
+ end
85
+
86
+ def migrations_paths
87
+ @migrations_paths ||= Rails.application.paths["db/migrate"].to_a
88
+ end
89
+
90
+ def fixtures_path
91
+ @fixtures_path ||= if ENV["FIXTURES_PATH"]
92
+ File.join(root, ENV["FIXTURES_PATH"])
93
+ else
94
+ File.join(root, "test", "fixtures")
95
+ end
96
+ end
97
+
98
+ def root
99
+ @root ||= Rails.root
100
+ end
101
+
102
+ def env
103
+ @env ||= Rails.env
104
+ end
105
+
106
+ def spec
107
+ @spec ||= "primary"
108
+ end
109
+
110
+ def seed_loader
111
+ @seed_loader ||= Rails.application
112
+ end
113
+
114
+ def current_config(options = {})
115
+ options.reverse_merge! env: env
116
+ options[:spec] ||= "primary"
117
+ if options.has_key?(:config)
118
+ @current_config = options[:config]
119
+ else
120
+ @current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: options[:env], spec_name: options[:spec]).config
121
+ end
122
+ end
123
+
124
+ def create(*arguments)
125
+ configuration = arguments.first
126
+ class_for_adapter(configuration["adapter"]).new(*arguments).create
127
+ $stdout.puts "Created database '#{configuration['database']}'" if verbose?
128
+ rescue DatabaseAlreadyExists
129
+ $stderr.puts "Database '#{configuration['database']}' already exists" if verbose?
130
+ rescue Exception => error
131
+ $stderr.puts error
132
+ $stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
133
+ raise
134
+ end
135
+
136
+ def create_all
137
+ old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
138
+ each_local_configuration { |configuration| create configuration }
139
+ if old_pool
140
+ ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.to_hash)
141
+ end
142
+ end
143
+
144
+ def setup_initial_database_yaml
145
+ return {} unless defined?(Rails)
146
+
147
+ begin
148
+ Rails.application.config.load_database_yaml
149
+ rescue
150
+ $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
151
+
152
+ {}
153
+ end
154
+ end
155
+
156
+ def for_each(databases)
157
+ return {} unless defined?(Rails)
158
+
159
+ database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
160
+
161
+ # if this is a single database application we don't want tasks for each primary database
162
+ return if database_configs.count == 1
163
+
164
+ database_configs.each do |db_config|
165
+ yield db_config.spec_name
166
+ end
167
+ end
168
+
169
+ def raise_for_multi_db(environment = env, command:)
170
+ db_configs = ActiveRecord::Base.configurations.configs_for(env_name: environment)
171
+
172
+ if db_configs.count > 1
173
+ dbs_list = []
174
+
175
+ db_configs.each do |db|
176
+ dbs_list << "#{command}:#{db.spec_name}"
177
+ end
178
+
179
+ raise "You're using a multiple database application. To use `#{command}` you must run the namespaced task with a VERSION. Available tasks are #{dbs_list.to_sentence}."
180
+ end
181
+ end
182
+
183
+ def create_current(environment = env, spec_name = nil)
184
+ each_current_configuration(environment, spec_name) { |configuration|
185
+ create configuration
186
+ }
187
+ ActiveRecord::Base.establish_connection(environment.to_sym)
188
+ end
189
+
190
+ def drop(*arguments)
191
+ configuration = arguments.first
192
+ class_for_adapter(configuration["adapter"]).new(*arguments).drop
193
+ $stdout.puts "Dropped database '#{configuration['database']}'" if verbose?
194
+ rescue ActiveRecord::NoDatabaseError
195
+ $stderr.puts "Database '#{configuration['database']}' does not exist"
196
+ rescue Exception => error
197
+ $stderr.puts error
198
+ $stderr.puts "Couldn't drop database '#{configuration['database']}'"
199
+ raise
200
+ end
201
+
202
+ def drop_all
203
+ each_local_configuration { |configuration| drop configuration }
204
+ end
205
+
206
+ def drop_current(environment = env)
207
+ each_current_configuration(environment) { |configuration|
208
+ drop configuration
209
+ }
210
+ end
211
+
212
+ def truncate_tables(configuration)
213
+ ActiveRecord::Base.connected_to(database: { truncation: configuration }) do
214
+ conn = ActiveRecord::Base.connection
215
+ table_names = conn.tables
216
+ table_names -= [
217
+ conn.schema_migration.table_name,
218
+ InternalMetadata.table_name
219
+ ]
220
+
221
+ ActiveRecord::Base.connection.truncate_tables(*table_names)
222
+ end
223
+ end
224
+ private :truncate_tables
225
+
226
+ def truncate_all(environment = env)
227
+ ActiveRecord::Base.configurations.configs_for(env_name: environment).each do |db_config|
228
+ truncate_tables db_config.config
229
+ end
230
+ end
231
+
232
+ def migrate
233
+ check_target_version
234
+
235
+ scope = ENV["SCOPE"]
236
+ verbose_was, Migration.verbose = Migration.verbose, verbose?
237
+
238
+ Base.connection.migration_context.migrate(target_version) do |migration|
239
+ scope.blank? || scope == migration.scope
240
+ end
241
+
242
+ ActiveRecord::Base.clear_cache!
243
+ ensure
244
+ Migration.verbose = verbose_was
245
+ end
246
+
247
+ def migrate_status
248
+ unless ActiveRecord::Base.connection.schema_migration.table_exists?
249
+ Kernel.abort "Schema migrations table does not exist yet."
250
+ end
251
+
252
+ # output
253
+ puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
254
+ puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
255
+ puts "-" * 50
256
+ ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
257
+ puts "#{status.center(8)} #{version.ljust(14)} #{name}"
258
+ end
259
+ puts
260
+ end
261
+
262
+ def check_target_version
263
+ if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
264
+ raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
265
+ end
266
+ end
267
+
268
+ def target_version
269
+ ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
270
+ end
271
+
272
+ def charset_current(environment = env, specification_name = spec)
273
+ charset ActiveRecord::Base.configurations.configs_for(env_name: environment, spec_name: specification_name).config
274
+ end
275
+
276
+ def charset(*arguments)
277
+ configuration = arguments.first
278
+ class_for_adapter(configuration["adapter"]).new(*arguments).charset
279
+ end
280
+
281
+ def collation_current(environment = env, specification_name = spec)
282
+ collation ActiveRecord::Base.configurations.configs_for(env_name: environment, spec_name: specification_name).config
283
+ end
284
+
285
+ def collation(*arguments)
286
+ configuration = arguments.first
287
+ class_for_adapter(configuration["adapter"]).new(*arguments).collation
288
+ end
289
+
290
+ def purge(configuration)
291
+ class_for_adapter(configuration["adapter"]).new(configuration).purge
292
+ end
293
+
294
+ def purge_all
295
+ each_local_configuration { |configuration|
296
+ purge configuration
297
+ }
298
+ end
299
+
300
+ def purge_current(environment = env)
301
+ each_current_configuration(environment) { |configuration|
302
+ purge configuration
303
+ }
304
+ ActiveRecord::Base.establish_connection(environment.to_sym)
305
+ end
306
+
307
+ def structure_dump(*arguments)
308
+ configuration = arguments.first
309
+ filename = arguments.delete_at 1
310
+ class_for_adapter(configuration["adapter"]).new(*arguments).structure_dump(filename, structure_dump_flags)
311
+ end
312
+
313
+ def structure_load(*arguments)
314
+ configuration = arguments.first
315
+ filename = arguments.delete_at 1
316
+ class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
317
+ end
318
+
319
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary") # :nodoc:
320
+ file ||= dump_filename(spec_name, format)
321
+
322
+ verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
323
+ check_schema_file(file)
324
+ ActiveRecord::Base.establish_connection(configuration)
325
+
326
+ case format
327
+ when :ruby
328
+ load(file)
329
+ when :sql
330
+ structure_load(configuration, file)
331
+ else
332
+ raise ArgumentError, "unknown format #{format.inspect}"
333
+ end
334
+ ActiveRecord::InternalMetadata.create_table
335
+ ActiveRecord::InternalMetadata[:environment] = environment
336
+ ActiveRecord::InternalMetadata[:schema_sha1] = schema_sha1(file)
337
+ ensure
338
+ Migration.verbose = verbose_was
339
+ end
340
+
341
+ def schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary")
342
+ file ||= dump_filename(spec_name, format)
343
+
344
+ return true unless File.exist?(file)
345
+
346
+ ActiveRecord::Base.establish_connection(configuration)
347
+ return false unless ActiveRecord::InternalMetadata.table_exists?
348
+ ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
349
+ end
350
+
351
+ def reconstruct_from_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary") # :nodoc:
352
+ file ||= dump_filename(spec_name, format)
353
+
354
+ check_schema_file(file)
355
+
356
+ ActiveRecord::Base.establish_connection(configuration)
357
+
358
+ if schema_up_to_date?(configuration, format, file, environment, spec_name)
359
+ truncate_tables(configuration)
360
+ else
361
+ purge(configuration)
362
+ load_schema(configuration, format, file, environment, spec_name)
363
+ end
364
+ rescue ActiveRecord::NoDatabaseError
365
+ create(configuration)
366
+ load_schema(configuration, format, file, environment, spec_name)
367
+ end
368
+
369
+ def dump_schema(configuration, format = ActiveRecord::Base.schema_format, spec_name = "primary") # :nodoc:
370
+ require "active_record/schema_dumper"
371
+ filename = dump_filename(spec_name, format)
372
+ connection = ActiveRecord::Base.connection
373
+
374
+ case format
375
+ when :ruby
376
+ File.open(filename, "w:utf-8") do |file|
377
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
378
+ end
379
+ when :sql
380
+ structure_dump(configuration, filename)
381
+ if connection.schema_migration.table_exists?
382
+ File.open(filename, "a") do |f|
383
+ f.puts connection.dump_schema_information
384
+ f.print "\n"
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ def schema_file(format = ActiveRecord::Base.schema_format)
391
+ File.join(db_dir, schema_file_type(format))
392
+ end
393
+
394
+ def schema_file_type(format = ActiveRecord::Base.schema_format)
395
+ case format
396
+ when :ruby
397
+ "schema.rb"
398
+ when :sql
399
+ "structure.sql"
400
+ end
401
+ end
402
+
403
+ def dump_filename(namespace, format = ActiveRecord::Base.schema_format)
404
+ filename = if namespace == "primary"
405
+ schema_file_type(format)
406
+ else
407
+ "#{namespace}_#{schema_file_type(format)}"
408
+ end
409
+
410
+ ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
411
+ end
412
+
413
+ def cache_dump_filename(namespace)
414
+ filename = if namespace == "primary"
415
+ "schema_cache.yml"
416
+ else
417
+ "#{namespace}_schema_cache.yml"
418
+ end
419
+
420
+ ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
421
+ end
422
+
423
+ def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
424
+ each_current_configuration(environment) { |configuration, spec_name, env|
425
+ load_schema(configuration, format, file, env, spec_name)
426
+ }
427
+ ActiveRecord::Base.establish_connection(environment.to_sym)
428
+ end
429
+
430
+ def check_schema_file(filename)
431
+ unless File.exist?(filename)
432
+ message = +%{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
433
+ message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
434
+ Kernel.abort message
435
+ end
436
+ end
437
+
438
+ def load_seed
439
+ if seed_loader
440
+ seed_loader.load_seed
441
+ else
442
+ raise "You tried to load seed data, but no seed loader is specified. Please specify seed " \
443
+ "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" \
444
+ "Seed loader should respond to load_seed method"
445
+ end
446
+ end
447
+
448
+ # Dumps the schema cache in YAML format for the connection into the file
449
+ #
450
+ # ==== Examples:
451
+ # ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
452
+ def dump_schema_cache(conn, filename)
453
+ conn.schema_cache.clear!
454
+ conn.data_sources.each { |table| conn.schema_cache.add(table) }
455
+ open(filename, "wb") { |f| f.write(YAML.dump(conn.schema_cache)) }
456
+ end
457
+
458
+ private
459
+ def verbose?
460
+ ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
461
+ end
462
+
463
+ def class_for_adapter(adapter)
464
+ _key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
465
+ unless task
466
+ raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
467
+ end
468
+ task.is_a?(String) ? task.constantize : task
469
+ end
470
+
471
+ def each_current_configuration(environment, spec_name = nil)
472
+ environments = [environment]
473
+ environments << "test" if environment == "development"
474
+
475
+ environments.each do |env|
476
+ ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
477
+ next if spec_name && spec_name != db_config.spec_name
478
+
479
+ yield db_config.config, db_config.spec_name, env
480
+ end
481
+ end
482
+ end
483
+
484
+ def each_local_configuration
485
+ ActiveRecord::Base.configurations.configs_for.each do |db_config|
486
+ configuration = db_config.config
487
+ next unless configuration["database"]
488
+
489
+ if local_database?(configuration)
490
+ yield configuration
491
+ else
492
+ $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
493
+ end
494
+ end
495
+ end
496
+
497
+ def local_database?(configuration)
498
+ configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
499
+ end
500
+
501
+ def schema_sha1(file)
502
+ Digest::SHA1.hexdigest(File.read(file))
503
+ end
504
+ end
505
+ end
506
+ end