activerecord 5.2.4.3 → 6.0.2.2

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

Potentially problematic release.


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

Files changed (269) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +715 -571
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +9 -2
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/association_relation.rb +15 -6
  9. data/lib/active_record/associations.rb +20 -15
  10. data/lib/active_record/associations/association.rb +61 -20
  11. data/lib/active_record/associations/association_scope.rb +4 -6
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +12 -23
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -10
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency.rb +28 -28
  29. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +39 -31
  32. data/lib/active_record/associations/preloader/association.rb +38 -36
  33. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/attribute_assignment.rb +7 -10
  36. data/lib/active_record/attribute_methods.rb +28 -100
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  38. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  40. data/lib/active_record/attribute_methods/query.rb +2 -3
  41. data/lib/active_record/attribute_methods/read.rb +15 -53
  42. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  44. data/lib/active_record/attribute_methods/write.rb +17 -24
  45. data/lib/active_record/attributes.rb +13 -0
  46. data/lib/active_record/autosave_association.rb +2 -2
  47. data/lib/active_record/base.rb +2 -3
  48. data/lib/active_record/callbacks.rb +5 -19
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +104 -16
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +187 -43
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
  61. data/lib/active_record/connection_adapters/column.rb +17 -13
  62. data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
  63. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  66. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  67. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  68. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  69. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  70. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  71. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  72. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  81. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  82. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  83. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  86. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  87. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  88. data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
  89. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  90. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  93. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  94. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +129 -141
  95. data/lib/active_record/connection_handling.rb +155 -26
  96. data/lib/active_record/core.rb +103 -59
  97. data/lib/active_record/counter_cache.rb +4 -29
  98. data/lib/active_record/database_configurations.rb +233 -0
  99. data/lib/active_record/database_configurations/database_config.rb +37 -0
  100. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  101. data/lib/active_record/database_configurations/url_config.rb +79 -0
  102. data/lib/active_record/dynamic_matchers.rb +1 -1
  103. data/lib/active_record/enum.rb +37 -7
  104. data/lib/active_record/errors.rb +15 -7
  105. data/lib/active_record/explain.rb +1 -1
  106. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  107. data/lib/active_record/fixture_set/render_context.rb +17 -0
  108. data/lib/active_record/fixture_set/table_row.rb +153 -0
  109. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  110. data/lib/active_record/fixtures.rb +145 -472
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +13 -3
  113. data/lib/active_record/insert_all.rb +179 -0
  114. data/lib/active_record/integration.rb +68 -16
  115. data/lib/active_record/internal_metadata.rb +10 -2
  116. data/lib/active_record/locking/optimistic.rb +5 -6
  117. data/lib/active_record/locking/pessimistic.rb +3 -3
  118. data/lib/active_record/log_subscriber.rb +7 -26
  119. data/lib/active_record/middleware/database_selector.rb +75 -0
  120. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  121. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  122. data/lib/active_record/migration.rb +100 -81
  123. data/lib/active_record/migration/command_recorder.rb +50 -6
  124. data/lib/active_record/migration/compatibility.rb +76 -49
  125. data/lib/active_record/model_schema.rb +33 -9
  126. data/lib/active_record/nested_attributes.rb +2 -2
  127. data/lib/active_record/no_touching.rb +7 -0
  128. data/lib/active_record/persistence.rb +228 -24
  129. data/lib/active_record/query_cache.rb +11 -4
  130. data/lib/active_record/querying.rb +32 -20
  131. data/lib/active_record/railtie.rb +80 -43
  132. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  133. data/lib/active_record/railties/controller_runtime.rb +30 -35
  134. data/lib/active_record/railties/databases.rake +199 -46
  135. data/lib/active_record/reflection.rb +32 -30
  136. data/lib/active_record/relation.rb +311 -80
  137. data/lib/active_record/relation/batches.rb +13 -10
  138. data/lib/active_record/relation/calculations.rb +53 -47
  139. data/lib/active_record/relation/delegation.rb +26 -43
  140. data/lib/active_record/relation/finder_methods.rb +23 -27
  141. data/lib/active_record/relation/merger.rb +11 -20
  142. data/lib/active_record/relation/predicate_builder.rb +4 -6
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  145. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  146. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  147. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  148. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  149. data/lib/active_record/relation/query_attribute.rb +13 -8
  150. data/lib/active_record/relation/query_methods.rb +213 -64
  151. data/lib/active_record/relation/spawn_methods.rb +1 -1
  152. data/lib/active_record/relation/where_clause.rb +14 -10
  153. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  154. data/lib/active_record/result.rb +30 -11
  155. data/lib/active_record/sanitization.rb +32 -40
  156. data/lib/active_record/schema.rb +2 -11
  157. data/lib/active_record/schema_dumper.rb +22 -7
  158. data/lib/active_record/schema_migration.rb +5 -1
  159. data/lib/active_record/scoping.rb +8 -8
  160. data/lib/active_record/scoping/default.rb +4 -5
  161. data/lib/active_record/scoping/named.rb +20 -15
  162. data/lib/active_record/statement_cache.rb +30 -3
  163. data/lib/active_record/store.rb +87 -8
  164. data/lib/active_record/table_metadata.rb +10 -17
  165. data/lib/active_record/tasks/database_tasks.rb +194 -25
  166. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  167. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  168. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  169. data/lib/active_record/test_databases.rb +23 -0
  170. data/lib/active_record/test_fixtures.rb +225 -0
  171. data/lib/active_record/timestamp.rb +39 -25
  172. data/lib/active_record/touch_later.rb +4 -2
  173. data/lib/active_record/transactions.rb +56 -65
  174. data/lib/active_record/translation.rb +1 -1
  175. data/lib/active_record/type.rb +3 -4
  176. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  177. data/lib/active_record/type_caster/connection.rb +15 -14
  178. data/lib/active_record/type_caster/map.rb +1 -4
  179. data/lib/active_record/validations.rb +1 -0
  180. data/lib/active_record/validations/uniqueness.rb +15 -27
  181. data/lib/arel.rb +58 -0
  182. data/lib/arel/alias_predication.rb +9 -0
  183. data/lib/arel/attributes.rb +22 -0
  184. data/lib/arel/attributes/attribute.rb +37 -0
  185. data/lib/arel/collectors/bind.rb +24 -0
  186. data/lib/arel/collectors/composite.rb +31 -0
  187. data/lib/arel/collectors/plain_string.rb +20 -0
  188. data/lib/arel/collectors/sql_string.rb +20 -0
  189. data/lib/arel/collectors/substitute_binds.rb +28 -0
  190. data/lib/arel/crud.rb +42 -0
  191. data/lib/arel/delete_manager.rb +18 -0
  192. data/lib/arel/errors.rb +9 -0
  193. data/lib/arel/expressions.rb +29 -0
  194. data/lib/arel/factory_methods.rb +49 -0
  195. data/lib/arel/insert_manager.rb +49 -0
  196. data/lib/arel/math.rb +45 -0
  197. data/lib/arel/nodes.rb +68 -0
  198. data/lib/arel/nodes/and.rb +32 -0
  199. data/lib/arel/nodes/ascending.rb +23 -0
  200. data/lib/arel/nodes/binary.rb +52 -0
  201. data/lib/arel/nodes/bind_param.rb +36 -0
  202. data/lib/arel/nodes/case.rb +55 -0
  203. data/lib/arel/nodes/casted.rb +50 -0
  204. data/lib/arel/nodes/comment.rb +29 -0
  205. data/lib/arel/nodes/count.rb +12 -0
  206. data/lib/arel/nodes/delete_statement.rb +45 -0
  207. data/lib/arel/nodes/descending.rb +23 -0
  208. data/lib/arel/nodes/equality.rb +18 -0
  209. data/lib/arel/nodes/extract.rb +24 -0
  210. data/lib/arel/nodes/false.rb +16 -0
  211. data/lib/arel/nodes/full_outer_join.rb +8 -0
  212. data/lib/arel/nodes/function.rb +44 -0
  213. data/lib/arel/nodes/grouping.rb +8 -0
  214. data/lib/arel/nodes/in.rb +8 -0
  215. data/lib/arel/nodes/infix_operation.rb +80 -0
  216. data/lib/arel/nodes/inner_join.rb +8 -0
  217. data/lib/arel/nodes/insert_statement.rb +37 -0
  218. data/lib/arel/nodes/join_source.rb +20 -0
  219. data/lib/arel/nodes/matches.rb +18 -0
  220. data/lib/arel/nodes/named_function.rb +23 -0
  221. data/lib/arel/nodes/node.rb +50 -0
  222. data/lib/arel/nodes/node_expression.rb +13 -0
  223. data/lib/arel/nodes/outer_join.rb +8 -0
  224. data/lib/arel/nodes/over.rb +15 -0
  225. data/lib/arel/nodes/regexp.rb +16 -0
  226. data/lib/arel/nodes/right_outer_join.rb +8 -0
  227. data/lib/arel/nodes/select_core.rb +67 -0
  228. data/lib/arel/nodes/select_statement.rb +41 -0
  229. data/lib/arel/nodes/sql_literal.rb +16 -0
  230. data/lib/arel/nodes/string_join.rb +11 -0
  231. data/lib/arel/nodes/table_alias.rb +27 -0
  232. data/lib/arel/nodes/terminal.rb +16 -0
  233. data/lib/arel/nodes/true.rb +16 -0
  234. data/lib/arel/nodes/unary.rb +45 -0
  235. data/lib/arel/nodes/unary_operation.rb +20 -0
  236. data/lib/arel/nodes/unqualified_column.rb +22 -0
  237. data/lib/arel/nodes/update_statement.rb +41 -0
  238. data/lib/arel/nodes/values_list.rb +9 -0
  239. data/lib/arel/nodes/window.rb +126 -0
  240. data/lib/arel/nodes/with.rb +11 -0
  241. data/lib/arel/order_predications.rb +13 -0
  242. data/lib/arel/predications.rb +257 -0
  243. data/lib/arel/select_manager.rb +271 -0
  244. data/lib/arel/table.rb +110 -0
  245. data/lib/arel/tree_manager.rb +72 -0
  246. data/lib/arel/update_manager.rb +34 -0
  247. data/lib/arel/visitors.rb +20 -0
  248. data/lib/arel/visitors/depth_first.rb +204 -0
  249. data/lib/arel/visitors/dot.rb +297 -0
  250. data/lib/arel/visitors/ibm_db.rb +34 -0
  251. data/lib/arel/visitors/informix.rb +62 -0
  252. data/lib/arel/visitors/mssql.rb +157 -0
  253. data/lib/arel/visitors/mysql.rb +83 -0
  254. data/lib/arel/visitors/oracle.rb +159 -0
  255. data/lib/arel/visitors/oracle12.rb +66 -0
  256. data/lib/arel/visitors/postgresql.rb +110 -0
  257. data/lib/arel/visitors/sqlite.rb +39 -0
  258. data/lib/arel/visitors/to_sql.rb +889 -0
  259. data/lib/arel/visitors/visitor.rb +46 -0
  260. data/lib/arel/visitors/where_sql.rb +23 -0
  261. data/lib/arel/window_predications.rb +9 -0
  262. data/lib/rails/generators/active_record/migration.rb +14 -1
  263. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  264. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  265. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  266. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  267. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  268. metadata +111 -26
  269. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -26,15 +26,22 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  def self.run
29
- ActiveRecord::Base.connection_handler.connection_pool_list.
30
- reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
29
+ pools = []
30
+
31
+ ActiveRecord::Base.connection_handlers.each do |key, handler|
32
+ pools << handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
33
+ end
34
+
35
+ pools.flatten
31
36
  end
32
37
 
33
38
  def self.complete(pools)
34
39
  pools.each { |pool| pool.disable_query_cache! }
35
40
 
36
- ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
37
- pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
41
+ ActiveRecord::Base.connection_handlers.each do |_, handler|
42
+ handler.connection_pool_list.each do |pool|
43
+ pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
44
+ end
38
45
  end
39
46
  end
40
47
 
@@ -2,31 +2,36 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Querying
5
- delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
6
- delegate :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!, :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!, to: :all
7
- delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
8
- delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
9
- delegate :find_by, :find_by!, to: :all
10
- delegate :destroy_all, :delete_all, :update_all, to: :all
11
- delegate :find_each, :find_in_batches, :in_batches, to: :all
12
- delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
13
- :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
14
- :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
15
- delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
16
- delegate :pluck, :ids, to: :all
5
+ QUERYING_METHODS = [
6
+ :find, :find_by, :find_by!, :take, :take!, :first, :first!, :last, :last!,
7
+ :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
8
+ :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
9
+ :exists?, :any?, :many?, :none?, :one?,
10
+ :first_or_create, :first_or_create!, :first_or_initialize,
11
+ :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,
12
+ :create_or_find_by, :create_or_find_by!,
13
+ :destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
14
+ :find_each, :find_in_batches, :in_batches,
15
+ :select, :reselect, :order, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
16
+ :where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly, :extending, :or,
17
+ :having, :create_with, :distinct, :references, :none, :unscope, :optimizer_hints, :merge, :except, :only,
18
+ :count, :average, :minimum, :maximum, :sum, :calculate, :annotate,
19
+ :pluck, :pick, :ids
20
+ ].freeze # :nodoc:
21
+ delegate(*QUERYING_METHODS, to: :all)
17
22
 
18
23
  # Executes a custom SQL query against your database and returns all the results. The results will
19
- # be returned as an array with columns requested encapsulated as attributes of the model you call
20
- # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
24
+ # be returned as an array, with the requested columns encapsulated as attributes of the model you call
25
+ # this method from. For example, if you call <tt>Product.find_by_sql</tt>, then the results will be returned in
21
26
  # a +Product+ object with the attributes you specified in the SQL query.
22
27
  #
23
- # If you call a complicated SQL query which spans multiple tables the columns specified by the
28
+ # If you call a complicated SQL query which spans multiple tables, the columns specified by the
24
29
  # SELECT will be attributes of the model, whether or not they are columns of the corresponding
25
30
  # table.
26
31
  #
27
- # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
28
- # no database agnostic conversions performed. This should be a last resort because using, for example,
29
- # MySQL specific terms will lock you to using that particular database engine or require you to
32
+ # The +sql+ parameter is a full SQL query as a string. It will be called as is; there will be
33
+ # no database agnostic conversions performed. This should be a last resort because using
34
+ # database-specific terms will lock you into using that particular database engine, or require you to
30
35
  # change your call if you switch engines.
31
36
  #
32
37
  # # A simple SQL query spanning multiple tables
@@ -49,13 +54,20 @@ module ActiveRecord
49
54
  }
50
55
 
51
56
  message_bus.instrument("instantiation.active_record", payload) do
52
- result_set.map { |record| instantiate(record, column_types, &block) }
57
+ if result_set.includes_column?(inheritance_column)
58
+ result_set.map { |record| instantiate(record, column_types, &block) }
59
+ else
60
+ # Instantiate a homogeneous set
61
+ result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
62
+ end
53
63
  end
54
64
  end
55
65
 
56
66
  # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
57
67
  # The use of this method should be restricted to complicated SQL queries that can't be executed
58
- # using the ActiveRecord::Calculations class methods. Look into those before using this.
68
+ # using the ActiveRecord::Calculations class methods. Look into those before using this method,
69
+ # as it could lock you into a specific database engine or require a code change to switch
70
+ # database engines.
59
71
  #
60
72
  # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
61
73
  # # => 12
@@ -77,6 +77,10 @@ module ActiveRecord
77
77
  ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
78
78
  end
79
79
 
80
+ initializer "active_record.backtrace_cleaner" do
81
+ ActiveSupport.on_load(:active_record) { LogSubscriber.backtrace_cleaner = ::Rails.backtrace_cleaner }
82
+ end
83
+
80
84
  initializer "active_record.migration_error" do
81
85
  if config.active_record.delete(:migration_error) == :page_load
82
86
  config.app_middleware.insert_after ::ActionDispatch::Callbacks,
@@ -84,6 +88,39 @@ module ActiveRecord
84
88
  end
85
89
  end
86
90
 
91
+ initializer "active_record.database_selector" do
92
+ if options = config.active_record.delete(:database_selector)
93
+ resolver = config.active_record.delete(:database_resolver)
94
+ operations = config.active_record.delete(:database_resolver_context)
95
+ config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
96
+ end
97
+ end
98
+
99
+ initializer "Check for cache versioning support" do
100
+ config.after_initialize do |app|
101
+ ActiveSupport.on_load(:active_record) do
102
+ if app.config.active_record.cache_versioning && Rails.cache
103
+ unless Rails.cache.class.try(:supports_cache_versioning?)
104
+ raise <<-end_error
105
+
106
+ You're using a cache store that doesn't support native cache versioning.
107
+ Your best option is to upgrade to a newer version of #{Rails.cache.class}
108
+ that supports cache versioning (#{Rails.cache.class}.supports_cache_versioning? #=> true).
109
+
110
+ Next best, switch to a different cache store that does support cache versioning:
111
+ https://guides.rubyonrails.org/caching_with_rails.html#cache-stores.
112
+
113
+ To keep using the current cache store, you can turn off cache versioning entirely:
114
+
115
+ config.active_record.cache_versioning = false
116
+
117
+ end_error
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+
87
124
  initializer "active_record.check_schema_cache_dump" do
88
125
  if config.active_record.delete(:use_schema_cache_dump)
89
126
  config.after_initialize do |app|
@@ -97,7 +134,6 @@ module ActiveRecord
97
134
 
98
135
  cache = YAML.load(File.read(filename))
99
136
  if cache.version == current_version
100
- connection.schema_cache = cache
101
137
  connection_pool.schema_cache = cache.dup
102
138
  else
103
139
  warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
@@ -108,6 +144,26 @@ module ActiveRecord
108
144
  end
109
145
  end
110
146
 
147
+ initializer "active_record.define_attribute_methods" do |app|
148
+ config.after_initialize do
149
+ ActiveSupport.on_load(:active_record) do
150
+ if app.config.eager_load
151
+ descendants.each do |model|
152
+ # SchemaMigration and InternalMetadata both override `table_exists?`
153
+ # to bypass the schema cache, so skip them to avoid the extra queries.
154
+ next if model._internal?
155
+
156
+ # If there's no connection yet, or the schema cache doesn't have the columns
157
+ # hash for the model cached, `define_attribute_methods` would trigger a query.
158
+ next unless model.connected? && model.connection.schema_cache.columns_hash?(model.table_name)
159
+
160
+ model.define_attribute_methods
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+
111
167
  initializer "active_record.warn_on_records_fetched_greater_than" do
112
168
  if config.active_record.warn_on_records_fetched_greater_than
113
169
  ActiveSupport.on_load(:active_record) do
@@ -118,8 +174,18 @@ module ActiveRecord
118
174
 
119
175
  initializer "active_record.set_configs" do |app|
120
176
  ActiveSupport.on_load(:active_record) do
121
- configs = app.config.active_record.dup
177
+ configs = app.config.active_record
178
+
179
+ represent_boolean_as_integer = configs.sqlite3.delete(:represent_boolean_as_integer)
180
+
181
+ unless represent_boolean_as_integer.nil?
182
+ ActiveSupport.on_load(:active_record_sqlite3adapter) do
183
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
184
+ end
185
+ end
186
+
122
187
  configs.delete(:sqlite3)
188
+
123
189
  configs.each do |k, v|
124
190
  send "#{k}=", v
125
191
  end
@@ -130,22 +196,9 @@ module ActiveRecord
130
196
  # and then establishes the connection.
131
197
  initializer "active_record.initialize_database" do
132
198
  ActiveSupport.on_load(:active_record) do
199
+ self.connection_handlers = { writing_role => ActiveRecord::Base.default_connection_handler }
133
200
  self.configurations = Rails.application.config.database_configuration
134
-
135
- begin
136
- establish_connection
137
- rescue ActiveRecord::NoDatabaseError
138
- warn <<-end_warning
139
- Oops - You have a database configured, but it doesn't exist yet!
140
-
141
- Here's how to get started:
142
-
143
- 1. Configure your database in config/database.yml.
144
- 2. Run `bin/rails db:create` to create the database.
145
- 3. Run `bin/rails db:setup` to load your database schema.
146
- end_warning
147
- raise
148
- end
201
+ establish_connection
149
202
  end
150
203
  end
151
204
 
@@ -157,6 +210,13 @@ end_warning
157
210
  end
158
211
  end
159
212
 
213
+ initializer "active_record.collection_cache_association_loading" do
214
+ require "active_record/railties/collection_cache_association_loading"
215
+ ActiveSupport.on_load(:action_view) do
216
+ ActionView::PartialRenderer.prepend(ActiveRecord::Railties::CollectionCacheAssociationLoading)
217
+ end
218
+ end
219
+
160
220
  initializer "active_record.set_reloader_hooks" do
161
221
  ActiveSupport.on_load(:active_record) do
162
222
  ActiveSupport::Reloader.before_class_unload do
@@ -194,32 +254,9 @@ end_warning
194
254
  end
195
255
  end
196
256
 
197
- initializer "active_record.check_represent_sqlite3_boolean_as_integer" do
198
- config.after_initialize do
199
- ActiveSupport.on_load(:active_record_sqlite3adapter) do
200
- represent_boolean_as_integer = Rails.application.config.active_record.sqlite3.delete(:represent_boolean_as_integer)
201
- unless represent_boolean_as_integer.nil?
202
- ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
203
- end
204
-
205
- unless ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
206
- ActiveSupport::Deprecation.warn <<-MSG
207
- Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
208
- set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
209
- boolean values and must have old data converted to 1 and 0 (its native boolean
210
- serialization) before setting this flag to true. Conversion can be accomplished
211
- by setting up a rake task which runs
212
-
213
- ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
214
- ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
215
-
216
- for all models and all boolean columns, after which the flag must be set to
217
- true by adding the following to your application.rb file:
218
-
219
- Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
220
- MSG
221
- end
222
- end
257
+ initializer "active_record.set_filter_attributes" do
258
+ ActiveSupport.on_load(:active_record) do
259
+ self.filter_attributes += Rails.application.config.filter_parameters
223
260
  end
224
261
  end
225
262
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Railties # :nodoc:
5
+ module CollectionCacheAssociationLoading #:nodoc:
6
+ def setup(context, options, as, block)
7
+ @relation = relation_from_options(options)
8
+
9
+ super
10
+ end
11
+
12
+ def relation_from_options(cached: nil, partial: nil, collection: nil, **_)
13
+ return unless cached
14
+
15
+ relation = partial if partial.is_a?(ActiveRecord::Relation)
16
+ relation ||= collection if collection.is_a?(ActiveRecord::Relation)
17
+
18
+ if relation && !relation.loaded?
19
+ relation.skip_preloading!
20
+ end
21
+ end
22
+
23
+ def collection_without_template(*)
24
+ @relation.preload_associations(@collection) if @relation
25
+ super
26
+ end
27
+
28
+ def collection_with_template(*)
29
+ @relation.preload_associations(@collection) if @relation
30
+ super
31
+ end
32
+ end
33
+ end
34
+ end
@@ -8,49 +8,44 @@ module ActiveRecord
8
8
  module ControllerRuntime #:nodoc:
9
9
  extend ActiveSupport::Concern
10
10
 
11
- # TODO Change this to private once we've dropped Ruby 2.2 support.
12
- # Workaround for Ruby 2.2 "private attribute?" warning.
13
- protected
14
-
15
- attr_internal :db_runtime
16
-
17
- private
18
-
19
- def process_action(action, *args)
20
- # We also need to reset the runtime before each action
21
- # because of queries in middleware or in cases we are streaming
22
- # and it won't be cleaned up by the method below.
23
- ActiveRecord::LogSubscriber.reset_runtime
24
- super
11
+ module ClassMethods # :nodoc:
12
+ def log_process_action(payload)
13
+ messages, db_runtime = super, payload[:db_runtime]
14
+ messages << ("ActiveRecord: %.1fms" % db_runtime.to_f) if db_runtime
15
+ messages
16
+ end
25
17
  end
26
18
 
27
- def cleanup_view_runtime
28
- if logger && logger.info? && ActiveRecord::Base.connected?
29
- db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
30
- self.db_runtime = (db_runtime || 0) + db_rt_before_render
31
- runtime = super
32
- db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
33
- self.db_runtime += db_rt_after_render
34
- runtime - db_rt_after_render
35
- else
19
+ private
20
+ attr_internal :db_runtime
21
+
22
+ def process_action(action, *args)
23
+ # We also need to reset the runtime before each action
24
+ # because of queries in middleware or in cases we are streaming
25
+ # and it won't be cleaned up by the method below.
26
+ ActiveRecord::LogSubscriber.reset_runtime
36
27
  super
37
28
  end
38
- end
39
29
 
40
- def append_info_to_payload(payload)
41
- super
42
- if ActiveRecord::Base.connected?
43
- payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
30
+ def cleanup_view_runtime
31
+ if logger && logger.info? && ActiveRecord::Base.connected?
32
+ db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
33
+ self.db_runtime = (db_runtime || 0) + db_rt_before_render
34
+ runtime = super
35
+ db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
36
+ self.db_runtime += db_rt_after_render
37
+ runtime - db_rt_after_render
38
+ else
39
+ super
40
+ end
44
41
  end
45
- end
46
42
 
47
- module ClassMethods # :nodoc:
48
- def log_process_action(payload)
49
- messages, db_runtime = super, payload[:db_runtime]
50
- messages << ("ActiveRecord: %.1fms" % db_runtime.to_f) if db_runtime
51
- messages
43
+ def append_info_to_payload(payload)
44
+ super
45
+ if ActiveRecord::Base.connected?
46
+ payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
47
+ end
52
48
  end
53
- end
54
49
  end
55
50
  end
56
51
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require "active_record"
4
4
 
5
+ databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
6
+
5
7
  db_namespace = namespace :db do
6
8
  desc "Set the environment value for the database"
7
9
  task "environment:set" => :load_config do
@@ -22,6 +24,14 @@ db_namespace = namespace :db do
22
24
  task all: :load_config do
23
25
  ActiveRecord::Tasks::DatabaseTasks.create_all
24
26
  end
27
+
28
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
29
+ desc "Create #{spec_name} database for current environment"
30
+ task spec_name => :load_config do
31
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
32
+ ActiveRecord::Tasks::DatabaseTasks.create(db_config.config)
33
+ end
34
+ end
25
35
  end
26
36
 
27
37
  desc "Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to creating the development and test databases."
@@ -33,6 +43,14 @@ db_namespace = namespace :db do
33
43
  task all: [:load_config, :check_protected_environments] do
34
44
  ActiveRecord::Tasks::DatabaseTasks.drop_all
35
45
  end
46
+
47
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
48
+ desc "Drop #{spec_name} database for current environment"
49
+ task spec_name => [:load_config, :check_protected_environments] do
50
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
51
+ ActiveRecord::Tasks::DatabaseTasks.drop(db_config.config)
52
+ end
53
+ end
36
54
  end
37
55
 
38
56
  desc "Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to dropping the development and test databases."
@@ -50,6 +68,11 @@ db_namespace = namespace :db do
50
68
  end
51
69
  end
52
70
 
71
+ # desc "Truncates tables of each database for current environment"
72
+ task truncate_all: [:load_config, :check_protected_environments] do
73
+ ActiveRecord::Tasks::DatabaseTasks.truncate_all
74
+ end
75
+
53
76
  # desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:purge:all to purge all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases."
54
77
  task purge: [:load_config, :check_protected_environments] do
55
78
  ActiveRecord::Tasks::DatabaseTasks.purge_current
@@ -57,8 +80,14 @@ db_namespace = namespace :db do
57
80
 
58
81
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
59
82
  task migrate: :load_config do
60
- ActiveRecord::Tasks::DatabaseTasks.migrate
83
+ original_config = ActiveRecord::Base.connection_config
84
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
85
+ ActiveRecord::Base.establish_connection(db_config.config)
86
+ ActiveRecord::Tasks::DatabaseTasks.migrate
87
+ end
61
88
  db_namespace["_dump"].invoke
89
+ ensure
90
+ ActiveRecord::Base.establish_connection(original_config)
62
91
  end
63
92
 
64
93
  # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
@@ -77,6 +106,15 @@ db_namespace = namespace :db do
77
106
  end
78
107
 
79
108
  namespace :migrate do
109
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
110
+ desc "Migrate #{spec_name} database for current environment"
111
+ task spec_name => :load_config do
112
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
113
+ ActiveRecord::Base.establish_connection(db_config.config)
114
+ ActiveRecord::Tasks::DatabaseTasks.migrate
115
+ end
116
+ end
117
+
80
118
  # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
81
119
  task redo: :load_config do
82
120
  raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
@@ -95,6 +133,8 @@ db_namespace = namespace :db do
95
133
 
96
134
  # desc 'Runs the "up" for a given migration VERSION.'
97
135
  task up: :load_config do
136
+ ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
137
+
98
138
  raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
99
139
 
100
140
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
@@ -106,8 +146,29 @@ db_namespace = namespace :db do
106
146
  db_namespace["_dump"].invoke
107
147
  end
108
148
 
149
+ namespace :up do
150
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
151
+ task spec_name => :load_config do
152
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
153
+
154
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
155
+
156
+ ActiveRecord::Base.establish_connection(db_config.config)
157
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
158
+ ActiveRecord::Base.connection.migration_context.run(
159
+ :up,
160
+ ActiveRecord::Tasks::DatabaseTasks.target_version
161
+ )
162
+
163
+ db_namespace["_dump"].invoke
164
+ end
165
+ end
166
+ end
167
+
109
168
  # desc 'Runs the "down" for a given migration VERSION.'
110
169
  task down: :load_config do
170
+ ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:down")
171
+
111
172
  raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
112
173
 
113
174
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
@@ -119,20 +180,42 @@ db_namespace = namespace :db do
119
180
  db_namespace["_dump"].invoke
120
181
  end
121
182
 
183
+ namespace :down do
184
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
185
+ task spec_name => :load_config do
186
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
187
+
188
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
189
+
190
+ ActiveRecord::Base.establish_connection(db_config.config)
191
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
192
+ ActiveRecord::Base.connection.migration_context.run(
193
+ :down,
194
+ ActiveRecord::Tasks::DatabaseTasks.target_version
195
+ )
196
+
197
+ db_namespace["_dump"].invoke
198
+ end
199
+ end
200
+ end
201
+
122
202
  desc "Display status of migrations"
123
203
  task status: :load_config do
124
- unless ActiveRecord::SchemaMigration.table_exists?
125
- abort "Schema migrations table does not exist yet."
204
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
205
+ ActiveRecord::Base.establish_connection(db_config.config)
206
+ ActiveRecord::Tasks::DatabaseTasks.migrate_status
126
207
  end
208
+ end
127
209
 
128
- # output
129
- puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
130
- puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
131
- puts "-" * 50
132
- ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
133
- puts "#{status.center(8)} #{version.ljust(14)} #{name}"
210
+ namespace :status do
211
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
212
+ desc "Display status of migrations for #{spec_name} database"
213
+ task spec_name => :load_config do
214
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
215
+ ActiveRecord::Base.establish_connection(db_config.config)
216
+ ActiveRecord::Tasks::DatabaseTasks.migrate_status
217
+ end
134
218
  end
135
- puts
136
219
  end
137
220
  end
138
221
 
@@ -160,11 +243,9 @@ db_namespace = namespace :db do
160
243
 
161
244
  # desc "Retrieves the collation for the current environment's database"
162
245
  task collation: :load_config do
163
- begin
164
- puts ActiveRecord::Tasks::DatabaseTasks.collation_current
165
- rescue NoMethodError
166
- $stderr.puts "Sorry, your database adapter is not supported yet. Feel free to submit a patch."
167
- end
246
+ puts ActiveRecord::Tasks::DatabaseTasks.collation_current
247
+ rescue NoMethodError
248
+ $stderr.puts "Sorry, your database adapter is not supported yet. Feel free to submit a patch."
168
249
  end
169
250
 
170
251
  desc "Retrieves the current schema version number"
@@ -174,7 +255,11 @@ db_namespace = namespace :db do
174
255
 
175
256
  # desc "Raises an error if there are pending migrations"
176
257
  task abort_if_pending_migrations: :load_config do
177
- pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
258
+ pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config|
259
+ ActiveRecord::Base.establish_connection(db_config.config)
260
+
261
+ ActiveRecord::Base.connection.migration_context.open.pending_migrations
262
+ end
178
263
 
179
264
  if pending_migrations.any?
180
265
  puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -183,17 +268,74 @@ db_namespace = namespace :db do
183
268
  end
184
269
  abort %{Run `rails db:migrate` to update your database then try again.}
185
270
  end
271
+ ensure
272
+ ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
273
+ end
274
+
275
+ namespace :abort_if_pending_migrations do
276
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
277
+ # desc "Raises an error if there are pending migrations for #{spec_name} database"
278
+ task spec_name => :load_config do
279
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
280
+ ActiveRecord::Base.establish_connection(db_config.config)
281
+
282
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
283
+
284
+ if pending_migrations.any?
285
+ puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
286
+ pending_migrations.each do |pending_migration|
287
+ puts " %4d %s" % [pending_migration.version, pending_migration.name]
288
+ end
289
+ abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.}
290
+ end
291
+ end
292
+ end
186
293
  end
187
294
 
188
295
  desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
189
296
  task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed]
190
297
 
298
+ desc "Runs setup if database does not exist, or runs migrations if it does"
299
+ task prepare: :load_config do
300
+ seed = false
301
+
302
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
303
+ ActiveRecord::Base.establish_connection(db_config.config)
304
+
305
+ # Skipped when no database
306
+ ActiveRecord::Tasks::DatabaseTasks.migrate
307
+ if ActiveRecord::Base.dump_schema_after_migration
308
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, ActiveRecord::Base.schema_format, db_config.spec_name)
309
+ end
310
+
311
+ rescue ActiveRecord::NoDatabaseError
312
+ ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, db_config.spec_name)
313
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(
314
+ db_config.config,
315
+ ActiveRecord::Base.schema_format,
316
+ nil,
317
+ db_config.env_name,
318
+ db_config.spec_name
319
+ )
320
+
321
+ seed = true
322
+ end
323
+
324
+ ActiveRecord::Base.establish_connection
325
+ ActiveRecord::Tasks::DatabaseTasks.load_seed if seed
326
+ end
327
+
191
328
  desc "Loads the seed data from db/seeds.rb"
192
- task :seed do
329
+ task seed: :load_config do
193
330
  db_namespace["abort_if_pending_migrations"].invoke
194
331
  ActiveRecord::Tasks::DatabaseTasks.load_seed
195
332
  end
196
333
 
334
+ namespace :seed do
335
+ desc "Truncates tables of each database for current environment and loads the seeds"
336
+ task replant: [:load_config, :truncate_all, :seed]
337
+ end
338
+
197
339
  namespace :fixtures do
198
340
  desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
199
341
  task load: :load_config do
@@ -245,11 +387,11 @@ db_namespace = namespace :db do
245
387
  namespace :schema do
246
388
  desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
247
389
  task dump: :load_config do
248
- require "active_record/schema_dumper"
249
- filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema.rb")
250
- File.open(filename, "w:utf-8") do |file|
251
- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
390
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
391
+ ActiveRecord::Base.establish_connection(db_config.config)
392
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :ruby, db_config.spec_name)
252
393
  end
394
+
253
395
  db_namespace["schema:dump"].reenable
254
396
  end
255
397
 
@@ -265,33 +407,34 @@ db_namespace = namespace :db do
265
407
  namespace :cache do
266
408
  desc "Creates a db/schema_cache.yml file."
267
409
  task dump: :load_config do
268
- conn = ActiveRecord::Base.connection
269
- filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
270
- ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(conn, filename)
410
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
411
+ ActiveRecord::Base.establish_connection(db_config.config)
412
+ filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
413
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(
414
+ ActiveRecord::Base.connection,
415
+ filename,
416
+ )
417
+ end
271
418
  end
272
419
 
273
420
  desc "Clears a db/schema_cache.yml file."
274
421
  task clear: :load_config do
275
- filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
276
- rm_f filename, verbose: false
422
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
423
+ filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
424
+ rm_f filename, verbose: false
425
+ end
277
426
  end
278
427
  end
279
-
280
428
  end
281
429
 
282
430
  namespace :structure do
283
431
  desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
284
432
  task dump: :load_config do
285
- filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
286
- current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
287
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
288
-
289
- if ActiveRecord::SchemaMigration.table_exists?
290
- File.open(filename, "a") do |f|
291
- f.puts ActiveRecord::Base.connection.dump_schema_information
292
- f.print "\n"
293
- end
433
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
434
+ ActiveRecord::Base.establish_connection(db_config.config)
435
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :sql, db_config.spec_name)
294
436
  end
437
+
295
438
  db_namespace["structure:dump"].reenable
296
439
  end
297
440
 
@@ -318,25 +461,31 @@ db_namespace = namespace :db do
318
461
 
319
462
  # desc "Recreate the test database from an existent schema.rb file"
320
463
  task load_schema: %w(db:test:purge) do
321
- begin
322
- should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
323
- ActiveRecord::Schema.verbose = false
324
- ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :ruby, ENV["SCHEMA"], "test"
325
- ensure
326
- if should_reconnect
327
- ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
328
- end
464
+ should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
465
+ ActiveRecord::Schema.verbose = false
466
+ ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
467
+ filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :ruby)
468
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config.config, :ruby, filename, "test")
469
+ end
470
+ ensure
471
+ if should_reconnect
472
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations.default_hash(ActiveRecord::Tasks::DatabaseTasks.env))
329
473
  end
330
474
  end
331
475
 
332
476
  # desc "Recreate the test database from an existent structure.sql file"
333
477
  task load_structure: %w(db:test:purge) do
334
- ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :sql, ENV["SCHEMA"], "test"
478
+ ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
479
+ filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :sql)
480
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config.config, :sql, filename, "test")
481
+ end
335
482
  end
336
483
 
337
484
  # desc "Empty the test database"
338
485
  task purge: %w(load_config check_protected_environments) do
339
- ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations["test"]
486
+ ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
487
+ ActiveRecord::Tasks::DatabaseTasks.purge(db_config.config)
488
+ end
340
489
  end
341
490
 
342
491
  # desc 'Load the test schema'
@@ -360,6 +509,10 @@ namespace :railties do
360
509
  if railtie.respond_to?(:paths) && (path = railtie.paths["db/migrate"].first)
361
510
  railties[railtie.railtie_name] = path
362
511
  end
512
+
513
+ unless ENV["MIGRATIONS_PATH"].blank?
514
+ railties[railtie.railtie_name] = railtie.root + ENV["MIGRATIONS_PATH"]
515
+ end
363
516
  end
364
517
 
365
518
  on_skip = Proc.new do |name, migration|