activerecord 5.2.4.4 → 6.0.0.beta1

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

Potentially problematic release.


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

Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +300 -725
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +2 -1
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/associations.rb +16 -12
  9. data/lib/active_record/associations/association.rb +35 -19
  10. data/lib/active_record/associations/association_scope.rb +4 -6
  11. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +14 -50
  14. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  16. data/lib/active_record/associations/collection_association.rb +11 -25
  17. data/lib/active_record/associations/collection_proxy.rb +32 -6
  18. data/lib/active_record/associations/foreign_association.rb +7 -0
  19. data/lib/active_record/associations/has_many_association.rb +1 -1
  20. data/lib/active_record/associations/has_many_through_association.rb +25 -18
  21. data/lib/active_record/associations/has_one_association.rb +28 -30
  22. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  23. data/lib/active_record/associations/join_dependency.rb +15 -20
  24. data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
  25. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  26. data/lib/active_record/associations/preloader.rb +32 -29
  27. data/lib/active_record/associations/preloader/association.rb +1 -2
  28. data/lib/active_record/associations/singular_association.rb +2 -16
  29. data/lib/active_record/attribute_assignment.rb +7 -10
  30. data/lib/active_record/attribute_methods.rb +34 -56
  31. data/lib/active_record/attribute_methods/dirty.rb +64 -26
  32. data/lib/active_record/attribute_methods/primary_key.rb +8 -7
  33. data/lib/active_record/attribute_methods/read.rb +16 -48
  34. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  36. data/lib/active_record/attribute_methods/write.rb +15 -16
  37. data/lib/active_record/autosave_association.rb +7 -21
  38. data/lib/active_record/base.rb +2 -2
  39. data/lib/active_record/callbacks.rb +3 -17
  40. data/lib/active_record/collection_cache_key.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
  42. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  43. data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
  44. data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
  45. data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
  46. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
  47. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  48. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
  49. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
  50. data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
  51. data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
  52. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
  53. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  54. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
  55. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
  56. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  57. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  58. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
  60. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
  61. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
  62. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  64. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  65. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  66. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  67. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  68. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  69. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
  70. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
  72. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
  74. data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
  75. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
  78. data/lib/active_record/connection_handling.rb +132 -26
  79. data/lib/active_record/core.rb +76 -43
  80. data/lib/active_record/counter_cache.rb +4 -29
  81. data/lib/active_record/database_configurations.rb +184 -0
  82. data/lib/active_record/database_configurations/database_config.rb +37 -0
  83. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  84. data/lib/active_record/database_configurations/url_config.rb +74 -0
  85. data/lib/active_record/enum.rb +22 -7
  86. data/lib/active_record/errors.rb +24 -21
  87. data/lib/active_record/explain.rb +1 -1
  88. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  89. data/lib/active_record/fixture_set/render_context.rb +17 -0
  90. data/lib/active_record/fixture_set/table_row.rb +153 -0
  91. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  92. data/lib/active_record/fixtures.rb +140 -472
  93. data/lib/active_record/gem_version.rb +4 -4
  94. data/lib/active_record/inheritance.rb +12 -2
  95. data/lib/active_record/integration.rb +56 -16
  96. data/lib/active_record/internal_metadata.rb +5 -1
  97. data/lib/active_record/locking/optimistic.rb +2 -2
  98. data/lib/active_record/locking/pessimistic.rb +3 -3
  99. data/lib/active_record/log_subscriber.rb +7 -26
  100. data/lib/active_record/migration.rb +38 -37
  101. data/lib/active_record/migration/command_recorder.rb +35 -5
  102. data/lib/active_record/migration/compatibility.rb +34 -16
  103. data/lib/active_record/model_schema.rb +30 -9
  104. data/lib/active_record/nested_attributes.rb +2 -2
  105. data/lib/active_record/no_touching.rb +7 -0
  106. data/lib/active_record/persistence.rb +18 -7
  107. data/lib/active_record/query_cache.rb +11 -4
  108. data/lib/active_record/querying.rb +19 -11
  109. data/lib/active_record/railtie.rb +71 -42
  110. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  111. data/lib/active_record/railties/controller_runtime.rb +30 -35
  112. data/lib/active_record/railties/databases.rake +94 -43
  113. data/lib/active_record/reflection.rb +60 -44
  114. data/lib/active_record/relation.rb +150 -69
  115. data/lib/active_record/relation/batches.rb +13 -10
  116. data/lib/active_record/relation/calculations.rb +38 -28
  117. data/lib/active_record/relation/delegation.rb +4 -13
  118. data/lib/active_record/relation/finder_methods.rb +12 -25
  119. data/lib/active_record/relation/merger.rb +2 -6
  120. data/lib/active_record/relation/predicate_builder.rb +4 -6
  121. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  122. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  123. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  124. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  125. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  126. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  127. data/lib/active_record/relation/query_attribute.rb +15 -12
  128. data/lib/active_record/relation/query_methods.rb +29 -52
  129. data/lib/active_record/relation/where_clause.rb +4 -0
  130. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  131. data/lib/active_record/result.rb +30 -11
  132. data/lib/active_record/sanitization.rb +2 -39
  133. data/lib/active_record/schema.rb +1 -10
  134. data/lib/active_record/schema_dumper.rb +12 -6
  135. data/lib/active_record/schema_migration.rb +4 -0
  136. data/lib/active_record/scoping.rb +9 -8
  137. data/lib/active_record/scoping/default.rb +10 -3
  138. data/lib/active_record/scoping/named.rb +10 -14
  139. data/lib/active_record/statement_cache.rb +32 -5
  140. data/lib/active_record/store.rb +39 -8
  141. data/lib/active_record/table_metadata.rb +1 -4
  142. data/lib/active_record/tasks/database_tasks.rb +89 -23
  143. data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  146. data/lib/active_record/test_databases.rb +38 -0
  147. data/lib/active_record/test_fixtures.rb +224 -0
  148. data/lib/active_record/timestamp.rb +4 -6
  149. data/lib/active_record/transactions.rb +3 -22
  150. data/lib/active_record/translation.rb +1 -1
  151. data/lib/active_record/type.rb +3 -4
  152. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  153. data/lib/active_record/type_caster/connection.rb +1 -6
  154. data/lib/active_record/type_caster/map.rb +1 -4
  155. data/lib/active_record/validations/uniqueness.rb +13 -25
  156. data/lib/arel.rb +44 -0
  157. data/lib/arel/alias_predication.rb +9 -0
  158. data/lib/arel/attributes.rb +22 -0
  159. data/lib/arel/attributes/attribute.rb +37 -0
  160. data/lib/arel/collectors/bind.rb +24 -0
  161. data/lib/arel/collectors/composite.rb +31 -0
  162. data/lib/arel/collectors/plain_string.rb +20 -0
  163. data/lib/arel/collectors/sql_string.rb +20 -0
  164. data/lib/arel/collectors/substitute_binds.rb +28 -0
  165. data/lib/arel/crud.rb +42 -0
  166. data/lib/arel/delete_manager.rb +18 -0
  167. data/lib/arel/errors.rb +9 -0
  168. data/lib/arel/expressions.rb +29 -0
  169. data/lib/arel/factory_methods.rb +49 -0
  170. data/lib/arel/insert_manager.rb +49 -0
  171. data/lib/arel/math.rb +45 -0
  172. data/lib/arel/nodes.rb +67 -0
  173. data/lib/arel/nodes/and.rb +32 -0
  174. data/lib/arel/nodes/ascending.rb +23 -0
  175. data/lib/arel/nodes/binary.rb +52 -0
  176. data/lib/arel/nodes/bind_param.rb +36 -0
  177. data/lib/arel/nodes/case.rb +55 -0
  178. data/lib/arel/nodes/casted.rb +50 -0
  179. data/lib/arel/nodes/count.rb +12 -0
  180. data/lib/arel/nodes/delete_statement.rb +45 -0
  181. data/lib/arel/nodes/descending.rb +23 -0
  182. data/lib/arel/nodes/equality.rb +18 -0
  183. data/lib/arel/nodes/extract.rb +24 -0
  184. data/lib/arel/nodes/false.rb +16 -0
  185. data/lib/arel/nodes/full_outer_join.rb +8 -0
  186. data/lib/arel/nodes/function.rb +44 -0
  187. data/lib/arel/nodes/grouping.rb +8 -0
  188. data/lib/arel/nodes/in.rb +8 -0
  189. data/lib/arel/nodes/infix_operation.rb +80 -0
  190. data/lib/arel/nodes/inner_join.rb +8 -0
  191. data/lib/arel/nodes/insert_statement.rb +37 -0
  192. data/lib/arel/nodes/join_source.rb +20 -0
  193. data/lib/arel/nodes/matches.rb +18 -0
  194. data/lib/arel/nodes/named_function.rb +23 -0
  195. data/lib/arel/nodes/node.rb +50 -0
  196. data/lib/arel/nodes/node_expression.rb +13 -0
  197. data/lib/arel/nodes/outer_join.rb +8 -0
  198. data/lib/arel/nodes/over.rb +15 -0
  199. data/lib/arel/nodes/regexp.rb +16 -0
  200. data/lib/arel/nodes/right_outer_join.rb +8 -0
  201. data/lib/arel/nodes/select_core.rb +63 -0
  202. data/lib/arel/nodes/select_statement.rb +41 -0
  203. data/lib/arel/nodes/sql_literal.rb +16 -0
  204. data/lib/arel/nodes/string_join.rb +11 -0
  205. data/lib/arel/nodes/table_alias.rb +27 -0
  206. data/lib/arel/nodes/terminal.rb +16 -0
  207. data/lib/arel/nodes/true.rb +16 -0
  208. data/lib/arel/nodes/unary.rb +44 -0
  209. data/lib/arel/nodes/unary_operation.rb +20 -0
  210. data/lib/arel/nodes/unqualified_column.rb +22 -0
  211. data/lib/arel/nodes/update_statement.rb +41 -0
  212. data/lib/arel/nodes/values.rb +16 -0
  213. data/lib/arel/nodes/values_list.rb +24 -0
  214. data/lib/arel/nodes/window.rb +126 -0
  215. data/lib/arel/nodes/with.rb +11 -0
  216. data/lib/arel/order_predications.rb +13 -0
  217. data/lib/arel/predications.rb +257 -0
  218. data/lib/arel/select_manager.rb +271 -0
  219. data/lib/arel/table.rb +110 -0
  220. data/lib/arel/tree_manager.rb +72 -0
  221. data/lib/arel/update_manager.rb +34 -0
  222. data/lib/arel/visitors.rb +20 -0
  223. data/lib/arel/visitors/depth_first.rb +199 -0
  224. data/lib/arel/visitors/dot.rb +292 -0
  225. data/lib/arel/visitors/ibm_db.rb +21 -0
  226. data/lib/arel/visitors/informix.rb +56 -0
  227. data/lib/arel/visitors/mssql.rb +143 -0
  228. data/lib/arel/visitors/mysql.rb +83 -0
  229. data/lib/arel/visitors/oracle.rb +159 -0
  230. data/lib/arel/visitors/oracle12.rb +67 -0
  231. data/lib/arel/visitors/postgresql.rb +116 -0
  232. data/lib/arel/visitors/sqlite.rb +39 -0
  233. data/lib/arel/visitors/to_sql.rb +913 -0
  234. data/lib/arel/visitors/visitor.rb +42 -0
  235. data/lib/arel/visitors/where_sql.rb +23 -0
  236. data/lib/arel/window_predications.rb +9 -0
  237. data/lib/rails/generators/active_record/migration.rb +14 -1
  238. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  239. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  240. metadata +104 -26
@@ -51,20 +51,11 @@ module ActiveRecord
51
51
 
52
52
  if info[:version].present?
53
53
  ActiveRecord::SchemaMigration.create_table
54
- connection.assume_migrated_upto_version(info[:version], migrations_paths)
54
+ connection.assume_migrated_upto_version(info[:version])
55
55
  end
56
56
 
57
57
  ActiveRecord::InternalMetadata.create_table
58
58
  ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
59
59
  end
60
-
61
- private
62
- # Returns the migrations paths.
63
- #
64
- # ActiveRecord::Schema.new.migrations_paths
65
- # # => ["db/migrate"] # Rails migration path by default.
66
- def migrations_paths
67
- ActiveRecord::Migrator.migrations_paths
68
- end
69
60
  end
70
61
  end
@@ -17,6 +17,12 @@ module ActiveRecord
17
17
  # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
18
18
  cattr_accessor :ignore_tables, default: []
19
19
 
20
+ ##
21
+ # :singleton-method:
22
+ # Specify a custom regular expression matching foreign keys which name
23
+ # should not be dumped to db/schema.rb.
24
+ cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
25
+
20
26
  class << self
21
27
  def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
22
28
  connection.create_schema_dumper(generate_options(config)).dump(stream)
@@ -65,11 +71,11 @@ module ActiveRecord
65
71
  # of editing this file, please use the migrations feature of Active Record to
66
72
  # incrementally modify your database, and then regenerate this schema definition.
67
73
  #
68
- # Note that this schema.rb definition is the authoritative source for your
69
- # database schema. If you need to create the application database on another
70
- # system, you should be using db:schema:load, not running all the migrations
71
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
72
- # you'll amass, the slower it'll run and the greater likelihood for issues).
74
+ # This file is the source Rails uses to define your schema when running `rails
75
+ # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
76
+ # be faster and is potentially less error prone than running all of your
77
+ # migrations from scratch. Old migrations may fail to apply correctly if those
78
+ # migrations use external dependencies or application code.
73
79
  #
74
80
  # It's strongly recommended that you check this file into your version control system.
75
81
 
@@ -210,7 +216,7 @@ HEADER
210
216
  parts << "primary_key: #{foreign_key.primary_key.inspect}"
211
217
  end
212
218
 
213
- if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
219
+ if foreign_key.export_name_on_schema_dump?
214
220
  parts << "name: #{foreign_key.name.inspect}"
215
221
  end
216
222
 
@@ -10,6 +10,10 @@ module ActiveRecord
10
10
  # to be executed the next time.
11
11
  class SchemaMigration < ActiveRecord::Base # :nodoc:
12
12
  class << self
13
+ def _internal?
14
+ true
15
+ end
16
+
13
17
  def primary_key
14
18
  "version"
15
19
  end
@@ -12,14 +12,6 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ClassMethods # :nodoc:
15
- def current_scope(skip_inherited_scope = false)
16
- ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
17
- end
18
-
19
- def current_scope=(scope)
20
- ScopeRegistry.set_value_for(:current_scope, self, scope)
21
- end
22
-
23
15
  # Collects attributes from scopes that should be applied when creating
24
16
  # an AR instance for the particular class this is called on.
25
17
  def scope_attributes
@@ -30,6 +22,15 @@ module ActiveRecord
30
22
  def scope_attributes?
31
23
  current_scope
32
24
  end
25
+
26
+ private
27
+ def current_scope(skip_inherited_scope = false)
28
+ ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
29
+ end
30
+
31
+ def current_scope=(scope)
32
+ ScopeRegistry.set_value_for(:current_scope, self, scope)
33
+ end
33
34
  end
34
35
 
35
36
  def populate_with_current_scope_attributes # :nodoc:
@@ -31,7 +31,14 @@ module ActiveRecord
31
31
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
32
32
  # }
33
33
  def unscoped
34
- block_given? ? relation.scoping { yield } : relation
34
+ block_given? ? _scoping(relation) { yield } : relation
35
+ end
36
+
37
+ def _scoping(relation) # :nodoc:
38
+ previous, self.current_scope = current_scope(true), relation
39
+ yield
40
+ ensure
41
+ self.current_scope = previous
35
42
  end
36
43
 
37
44
  # Are there attributes associated with this scope?
@@ -86,8 +93,8 @@ module ActiveRecord
86
93
  # # Should return a scope, you can call 'super' here etc.
87
94
  # end
88
95
  # end
89
- def default_scope(scope = nil, &block) # :doc:
90
- scope = block if block_given?
96
+ def default_scope(scope = nil) # :doc:
97
+ scope = Proc.new if block_given?
91
98
 
92
99
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
93
100
  raise ArgumentError,
@@ -24,13 +24,13 @@ module ActiveRecord
24
24
  # You can define a scope that applies to all finders using
25
25
  # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
26
26
  def all
27
- current_scope = self.current_scope
27
+ scope = current_scope
28
28
 
29
- if current_scope
30
- if self == current_scope.klass
31
- current_scope.clone
29
+ if scope
30
+ if self == scope.klass
31
+ scope.clone
32
32
  else
33
- relation.merge!(current_scope)
33
+ relation.merge!(scope)
34
34
  end
35
35
  else
36
36
  default_scoped
@@ -38,9 +38,7 @@ module ActiveRecord
38
38
  end
39
39
 
40
40
  def scope_for_association(scope = relation) # :nodoc:
41
- current_scope = self.current_scope
42
-
43
- if current_scope && current_scope.empty_scope?
41
+ if current_scope&.empty_scope?
44
42
  scope
45
43
  else
46
44
  default_scoped(scope)
@@ -181,16 +179,14 @@ module ActiveRecord
181
179
  extension = Module.new(&block) if block
182
180
 
183
181
  if body.respond_to?(:to_proc)
184
- singleton_class.send(:define_method, name) do |*args|
185
- scope = all
186
- scope = scope._exec_scope(*args, &body)
182
+ singleton_class.define_method(name) do |*args|
183
+ scope = all._exec_scope(*args, &body)
187
184
  scope = scope.extending(extension) if extension
188
185
  scope
189
186
  end
190
187
  else
191
- singleton_class.send(:define_method, name) do |*args|
192
- scope = all
193
- scope = scope.scoping { body.call(*args) || scope }
188
+ singleton_class.define_method(name) do |*args|
189
+ scope = body.call(*args) || all
194
190
  scope = scope.extending(extension) if extension
195
191
  scope
196
192
  end
@@ -44,7 +44,7 @@ module ActiveRecord
44
44
  def initialize(values)
45
45
  @values = values
46
46
  @indexes = values.each_with_index.find_all { |thing, i|
47
- Arel::Nodes::BindParam === thing
47
+ Substitute === thing
48
48
  }.map(&:last)
49
49
  end
50
50
 
@@ -56,6 +56,28 @@ module ActiveRecord
56
56
  end
57
57
  end
58
58
 
59
+ class PartialQueryCollector
60
+ def initialize
61
+ @parts = []
62
+ @binds = []
63
+ end
64
+
65
+ def <<(str)
66
+ @parts << str
67
+ self
68
+ end
69
+
70
+ def add_bind(obj)
71
+ @binds << obj
72
+ @parts << Substitute.new
73
+ self
74
+ end
75
+
76
+ def value
77
+ [@parts, @binds]
78
+ end
79
+ end
80
+
59
81
  def self.query(sql)
60
82
  Query.new(sql)
61
83
  end
@@ -64,6 +86,10 @@ module ActiveRecord
64
86
  PartialQuery.new(values)
65
87
  end
66
88
 
89
+ def self.partial_query_collector
90
+ PartialQueryCollector.new
91
+ end
92
+
67
93
  class Params # :nodoc:
68
94
  def bind; Substitute.new; end
69
95
  end
@@ -87,8 +113,8 @@ module ActiveRecord
87
113
  end
88
114
  end
89
115
 
90
- def self.create(connection, callable = nil, &block)
91
- relation = (callable || block).call Params.new
116
+ def self.create(connection, block = Proc.new)
117
+ relation = block.call Params.new
92
118
  query_builder, binds = connection.cacheable_query(self, relation.arel)
93
119
  bind_map = BindMap.new(binds)
94
120
  new(query_builder, bind_map, relation.klass)
@@ -106,6 +132,8 @@ module ActiveRecord
106
132
  sql = query_builder.sql_for bind_values, connection
107
133
 
108
134
  klass.find_by_sql(sql, bind_values, preparable: true, &block)
135
+ rescue ::RangeError
136
+ nil
109
137
  end
110
138
 
111
139
  def self.unsupported_value?(value)
@@ -114,8 +142,7 @@ module ActiveRecord
114
142
  end
115
143
  end
116
144
 
117
- protected
118
-
145
+ private
119
146
  attr_reader :query_builder, :bind_map, :klass
120
147
  end
121
148
  end
@@ -17,8 +17,8 @@ module ActiveRecord
17
17
  # You can set custom coder to encode/decode your serialized attributes to/from different formats.
18
18
  # JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
19
19
  #
20
- # NOTE: If you are using PostgreSQL specific columns like +hstore+ or +json+ there is no need for
21
- # the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
20
+ # NOTE: If you are using structured database data types (eg. PostgreSQL +hstore+/+json+, or MySQL 5.7+
21
+ # +json+) there is no need for the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
22
22
  # Simply use {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead to generate
23
23
  # the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
24
24
  # using a symbol.
@@ -31,10 +31,18 @@ module ActiveRecord
31
31
  #
32
32
  # class User < ActiveRecord::Base
33
33
  # store :settings, accessors: [ :color, :homepage ], coder: JSON
34
+ # store :parent, accessors: [ :name ], coder: JSON, prefix: true
35
+ # store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
36
+ # store :settings, accessors: [ :two_factor_auth ], suffix: true
37
+ # store :settings, accessors: [ :login_retry ], suffix: :config
34
38
  # end
35
39
  #
36
- # u = User.new(color: 'black', homepage: '37signals.com')
40
+ # u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily')
37
41
  # u.color # Accessor stored attribute
42
+ # u.parent_name # Accessor stored attribute with prefix
43
+ # u.partner_name # Accessor stored attribute with custom prefix
44
+ # u.two_factor_auth_settings # Accessor stored attribute with suffix
45
+ # u.login_retry_config # Accessor stored attribute with custom suffix
38
46
  # u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
39
47
  #
40
48
  # # There is no difference between strings and symbols for accessing custom attributes
@@ -44,11 +52,13 @@ module ActiveRecord
44
52
  # # Add additional accessors to an existing store through store_accessor
45
53
  # class SuperUser < User
46
54
  # store_accessor :settings, :privileges, :servants
55
+ # store_accessor :parent, :birthday, prefix: true
56
+ # store_accessor :settings, :secret_question, suffix: :config
47
57
  # end
48
58
  #
49
59
  # The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
50
60
  #
51
- # User.stored_attributes[:settings] # [:color, :homepage]
61
+ # User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
52
62
  #
53
63
  # == Overwriting default accessors
54
64
  #
@@ -81,19 +91,40 @@ module ActiveRecord
81
91
  module ClassMethods
82
92
  def store(store_attribute, options = {})
83
93
  serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
84
- store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
94
+ store_accessor(store_attribute, options[:accessors], options.slice(:prefix, :suffix)) if options.has_key? :accessors
85
95
  end
86
96
 
87
- def store_accessor(store_attribute, *keys)
97
+ def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
88
98
  keys = keys.flatten
89
99
 
100
+ accessor_prefix =
101
+ case prefix
102
+ when String, Symbol
103
+ "#{prefix}_"
104
+ when TrueClass
105
+ "#{store_attribute}_"
106
+ else
107
+ ""
108
+ end
109
+ accessor_suffix =
110
+ case suffix
111
+ when String, Symbol
112
+ "_#{suffix}"
113
+ when TrueClass
114
+ "_#{store_attribute}"
115
+ else
116
+ ""
117
+ end
118
+
90
119
  _store_accessors_module.module_eval do
91
120
  keys.each do |key|
92
- define_method("#{key}=") do |value|
121
+ accessor_key = "#{accessor_prefix}#{key}#{accessor_suffix}"
122
+
123
+ define_method("#{accessor_key}=") do |value|
93
124
  write_store_attribute(store_attribute, key, value)
94
125
  end
95
126
 
96
- define_method(key) do
127
+ define_method(accessor_key) do
97
128
  read_store_attribute(store_attribute, key)
98
129
  end
99
130
  end
@@ -73,10 +73,7 @@ module ActiveRecord
73
73
  klass.reflect_on_aggregation(aggregation_name)
74
74
  end
75
75
 
76
- # TODO Change this to private once we've dropped Ruby 2.2 support.
77
- # Workaround for Ruby 2.2 "private attribute?" warning.
78
- protected
79
-
76
+ private
80
77
  attr_reader :klass, :arel_table, :association
81
78
  end
82
79
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_record/database_configurations"
4
+
3
5
  module ActiveRecord
4
6
  module Tasks # :nodoc:
5
7
  class DatabaseAlreadyExists < StandardError; end # :nodoc:
@@ -8,7 +10,7 @@ module ActiveRecord
8
10
  # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
9
11
  # logic behind common tasks used to manage database and migrations.
10
12
  #
11
- # The tasks defined here are used with Rake tasks provided by Active Record.
13
+ # The tasks defined here are used with Rails commands provided by Active Record.
12
14
  #
13
15
  # In order to use DatabaseTasks, a few config values need to be set. All the needed
14
16
  # config values are set by Rails already, so it's necessary to do it only if you
@@ -101,25 +103,30 @@ module ActiveRecord
101
103
  @env ||= Rails.env
102
104
  end
103
105
 
106
+ def spec
107
+ @spec ||= "primary"
108
+ end
109
+
104
110
  def seed_loader
105
111
  @seed_loader ||= Rails.application
106
112
  end
107
113
 
108
114
  def current_config(options = {})
109
115
  options.reverse_merge! env: env
116
+ options[:spec] ||= "primary"
110
117
  if options.has_key?(:config)
111
118
  @current_config = options[:config]
112
119
  else
113
- @current_config ||= ActiveRecord::Base.configurations[options[:env]]
120
+ @current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: options[:env], spec_name: options[:spec]).config
114
121
  end
115
122
  end
116
123
 
117
124
  def create(*arguments)
118
125
  configuration = arguments.first
119
126
  class_for_adapter(configuration["adapter"]).new(*arguments).create
120
- $stdout.puts "Created database '#{configuration['database']}'"
127
+ $stdout.puts "Created database '#{configuration['database']}'" if verbose?
121
128
  rescue DatabaseAlreadyExists
122
- $stderr.puts "Database '#{configuration['database']}' already exists"
129
+ $stderr.puts "Database '#{configuration['database']}' already exists" if verbose?
123
130
  rescue Exception => error
124
131
  $stderr.puts error
125
132
  $stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
@@ -134,6 +141,18 @@ module ActiveRecord
134
141
  end
135
142
  end
136
143
 
144
+ def for_each
145
+ databases = Rails.application.config.database_configuration
146
+ database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
147
+
148
+ # if this is a single database application we don't want tasks for each primary database
149
+ return if database_configs.count == 1
150
+
151
+ database_configs.each do |db_config|
152
+ yield db_config.spec_name
153
+ end
154
+ end
155
+
137
156
  def create_current(environment = env)
138
157
  each_current_configuration(environment) { |configuration|
139
158
  create configuration
@@ -144,7 +163,7 @@ module ActiveRecord
144
163
  def drop(*arguments)
145
164
  configuration = arguments.first
146
165
  class_for_adapter(configuration["adapter"]).new(*arguments).drop
147
- $stdout.puts "Dropped database '#{configuration['database']}'"
166
+ $stdout.puts "Dropped database '#{configuration['database']}'" if verbose?
148
167
  rescue ActiveRecord::NoDatabaseError
149
168
  $stderr.puts "Database '#{configuration['database']}' does not exist"
150
169
  rescue Exception => error
@@ -166,17 +185,33 @@ module ActiveRecord
166
185
  def migrate
167
186
  check_target_version
168
187
 
169
- verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
170
188
  scope = ENV["SCOPE"]
171
- verbose_was, Migration.verbose = Migration.verbose, verbose
189
+ verbose_was, Migration.verbose = Migration.verbose, verbose?
190
+
172
191
  Base.connection.migration_context.migrate(target_version) do |migration|
173
192
  scope.blank? || scope == migration.scope
174
193
  end
194
+
175
195
  ActiveRecord::Base.clear_cache!
176
196
  ensure
177
197
  Migration.verbose = verbose_was
178
198
  end
179
199
 
200
+ def migrate_status
201
+ unless ActiveRecord::SchemaMigration.table_exists?
202
+ Kernel.abort "Schema migrations table does not exist yet."
203
+ end
204
+
205
+ # output
206
+ puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
207
+ puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
208
+ puts "-" * 50
209
+ ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
210
+ puts "#{status.center(8)} #{version.ljust(14)} #{name}"
211
+ end
212
+ puts
213
+ end
214
+
180
215
  def check_target_version
181
216
  if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
182
217
  raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
@@ -187,8 +222,8 @@ module ActiveRecord
187
222
  ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
188
223
  end
189
224
 
190
- def charset_current(environment = env)
191
- charset ActiveRecord::Base.configurations[environment]
225
+ def charset_current(environment = env, specification_name = spec)
226
+ charset ActiveRecord::Base.configurations.configs_for(env_name: environment, spec_name: specification_name).config
192
227
  end
193
228
 
194
229
  def charset(*arguments)
@@ -196,8 +231,8 @@ module ActiveRecord
196
231
  class_for_adapter(configuration["adapter"]).new(*arguments).charset
197
232
  end
198
233
 
199
- def collation_current(environment = env)
200
- collation ActiveRecord::Base.configurations[environment]
234
+ def collation_current(environment = env, specification_name = spec)
235
+ collation ActiveRecord::Base.configurations.configs_for(env_name: environment, spec_name: specification_name).config
201
236
  end
202
237
 
203
238
  def collation(*arguments)
@@ -234,9 +269,10 @@ module ActiveRecord
234
269
  class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
235
270
  end
236
271
 
237
- def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
238
- file ||= schema_file(format)
272
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary") # :nodoc:
273
+ file ||= dump_filename(spec_name, format)
239
274
 
275
+ verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
240
276
  check_schema_file(file)
241
277
  ActiveRecord::Base.establish_connection(configuration)
242
278
 
@@ -250,27 +286,53 @@ module ActiveRecord
250
286
  end
251
287
  ActiveRecord::InternalMetadata.create_table
252
288
  ActiveRecord::InternalMetadata[:environment] = environment
289
+ ensure
290
+ Migration.verbose = verbose_was
253
291
  end
254
292
 
255
293
  def schema_file(format = ActiveRecord::Base.schema_format)
294
+ File.join(db_dir, schema_file_type(format))
295
+ end
296
+
297
+ def schema_file_type(format = ActiveRecord::Base.schema_format)
256
298
  case format
257
299
  when :ruby
258
- File.join(db_dir, "schema.rb")
300
+ "schema.rb"
259
301
  when :sql
260
- File.join(db_dir, "structure.sql")
302
+ "structure.sql"
303
+ end
304
+ end
305
+
306
+ def dump_filename(namespace, format = ActiveRecord::Base.schema_format)
307
+ filename = if namespace == "primary"
308
+ schema_file_type(format)
309
+ else
310
+ "#{namespace}_#{schema_file_type(format)}"
311
+ end
312
+
313
+ ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
314
+ end
315
+
316
+ def cache_dump_filename(namespace)
317
+ filename = if namespace == "primary"
318
+ "schema_cache.yml"
319
+ else
320
+ "#{namespace}_schema_cache.yml"
261
321
  end
322
+
323
+ ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
262
324
  end
263
325
 
264
326
  def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
265
- each_current_configuration(environment) { |configuration, configuration_environment|
266
- load_schema configuration, format, file, configuration_environment
327
+ each_current_configuration(environment) { |configuration, spec_name, env|
328
+ load_schema(configuration, format, file, env, spec_name)
267
329
  }
268
330
  ActiveRecord::Base.establish_connection(environment.to_sym)
269
331
  end
270
332
 
271
333
  def check_schema_file(filename)
272
334
  unless File.exist?(filename)
273
- message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}.dup
335
+ message = +%{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
274
336
  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)
275
337
  Kernel.abort message
276
338
  end
@@ -297,6 +359,9 @@ module ActiveRecord
297
359
  end
298
360
 
299
361
  private
362
+ def verbose?
363
+ ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
364
+ end
300
365
 
301
366
  def class_for_adapter(adapter)
302
367
  _key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
@@ -310,15 +375,16 @@ module ActiveRecord
310
375
  environments = [environment]
311
376
  environments << "test" if environment == "development"
312
377
 
313
- ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
314
- next unless configuration["database"]
315
-
316
- yield configuration, configuration_environment
378
+ environments.each do |env|
379
+ ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
380
+ yield db_config.config, db_config.spec_name, env
381
+ end
317
382
  end
318
383
  end
319
384
 
320
385
  def each_local_configuration
321
- ActiveRecord::Base.configurations.each_value do |configuration|
386
+ ActiveRecord::Base.configurations.configs_for.each do |db_config|
387
+ configuration = db_config.config
322
388
  next unless configuration["database"]
323
389
 
324
390
  if local_database?(configuration)