activerecord 5.2.3.rc1 → 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 +326 -696
  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 +1 -1
  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 +14 -14
  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 +6 -0
  25. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  26. data/lib/active_record/associations/preloader.rb +31 -28
  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 +1 -1
  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 +10 -14
  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 +14 -11
  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 +40 -26
  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 +93 -60
  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 +46 -34
  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 +34 -23
  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 +26 -47
  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 +8 -1
  138. data/lib/active_record/scoping/named.rb +10 -14
  139. data/lib/active_record/statement_cache.rb +30 -3
  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 +2 -21
  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 +101 -23
@@ -85,7 +85,7 @@ module ActiveRecord
85
85
  # invert the +command+.
86
86
  def inverse_of(command, args, &block)
87
87
  method = :"invert_#{command}"
88
- raise IrreversibleMigration, <<-MSG.strip_heredoc unless respond_to?(method, true)
88
+ raise IrreversibleMigration, <<~MSG unless respond_to?(method, true)
89
89
  This migration uses #{command}, which is not automatically reversible.
90
90
  To make the migration reversible you can either:
91
91
  1. Define #up and #down methods in place of the #change method.
@@ -108,11 +108,17 @@ module ActiveRecord
108
108
  yield delegate.update_table_definition(table_name, self)
109
109
  end
110
110
 
111
+ def replay(migration)
112
+ commands.each do |cmd, args, block|
113
+ migration.send(cmd, *args, &block)
114
+ end
115
+ end
116
+
111
117
  private
112
118
 
113
119
  module StraightReversions # :nodoc:
114
120
  private
115
- { transaction: :transaction,
121
+ {
116
122
  execute_block: :execute_block,
117
123
  create_table: :drop_table,
118
124
  create_join_table: :drop_join_table,
@@ -133,6 +139,17 @@ module ActiveRecord
133
139
 
134
140
  include StraightReversions
135
141
 
142
+ def invert_transaction(args)
143
+ sub_recorder = CommandRecorder.new(delegate)
144
+ sub_recorder.revert { yield }
145
+
146
+ invertions_proc = proc {
147
+ sub_recorder.replay(self)
148
+ }
149
+
150
+ [:transaction, args, invertions_proc]
151
+ end
152
+
136
153
  def invert_drop_table(args, &block)
137
154
  if args.size == 1 && block == nil
138
155
  raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
@@ -214,11 +231,24 @@ module ActiveRecord
214
231
  end
215
232
 
216
233
  def invert_remove_foreign_key(args)
217
- from_table, to_table, remove_options = args
218
- raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash)
234
+ from_table, options_or_to_table, options_or_nil = args
235
+
236
+ to_table = if options_or_to_table.is_a?(Hash)
237
+ options_or_to_table[:to_table]
238
+ else
239
+ options_or_to_table
240
+ end
241
+
242
+ remove_options = if options_or_to_table.is_a?(Hash)
243
+ options_or_to_table.except(:to_table)
244
+ else
245
+ options_or_nil
246
+ end
247
+
248
+ raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil?
219
249
 
220
250
  reversed_args = [from_table, to_table]
221
- reversed_args << remove_options if remove_options
251
+ reversed_args << remove_options if remove_options.present?
222
252
 
223
253
  [:add_foreign_key, reversed_args]
224
254
  end
@@ -13,22 +13,42 @@ module ActiveRecord
13
13
  const_get(name)
14
14
  end
15
15
 
16
- V5_2 = Current
16
+ V6_0 = Current
17
+
18
+ class V5_2 < V6_0
19
+ module CommandRecorder
20
+ def invert_transaction(args, &block)
21
+ [:transaction, args, block]
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def command_recorder
28
+ recorder = super
29
+ class << recorder
30
+ prepend CommandRecorder
31
+ end
32
+ recorder
33
+ end
34
+ end
17
35
 
18
36
  class V5_1 < V5_2
19
37
  def change_column(table_name, column_name, type, options = {})
20
- if connection.adapter_name == "PostgreSQL"
21
- super(table_name, column_name, type, options.except(:default, :null, :comment))
22
- connection.change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
23
- connection.change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
24
- connection.change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
38
+ if adapter_name == "PostgreSQL"
39
+ clear_cache!
40
+ sql = connection.send(:change_column_sql, table_name, column_name, type, options)
41
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql}"
42
+ change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
43
+ change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
44
+ change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
25
45
  else
26
46
  super
27
47
  end
28
48
  end
29
49
 
30
50
  def create_table(table_name, options = {})
31
- if connection.adapter_name == "Mysql2"
51
+ if adapter_name == "Mysql2"
32
52
  super(table_name, options: "ENGINE=InnoDB", **options)
33
53
  else
34
54
  super
@@ -50,13 +70,13 @@ module ActiveRecord
50
70
  end
51
71
 
52
72
  def create_table(table_name, options = {})
53
- if connection.adapter_name == "PostgreSQL"
73
+ if adapter_name == "PostgreSQL"
54
74
  if options[:id] == :uuid && !options.key?(:default)
55
75
  options[:default] = "uuid_generate_v4()"
56
76
  end
57
77
  end
58
78
 
59
- unless connection.adapter_name == "Mysql2" && options[:id] == :bigint
79
+ unless adapter_name == "Mysql2" && options[:id] == :bigint
60
80
  if [:integer, :bigint].include?(options[:id]) && !options.key?(:default)
61
81
  options[:default] = nil
62
82
  end
@@ -173,7 +193,7 @@ module ActiveRecord
173
193
  if options[:name].present?
174
194
  options[:name].to_s
175
195
  else
176
- connection.index_name(table_name, column: column_names)
196
+ index_name(table_name, column: column_names)
177
197
  end
178
198
  super
179
199
  end
@@ -193,17 +213,15 @@ module ActiveRecord
193
213
  end
194
214
 
195
215
  def index_name_for_remove(table_name, options = {})
196
- index_name = connection.index_name(table_name, options)
216
+ index_name = index_name(table_name, options)
197
217
 
198
- unless connection.index_name_exists?(table_name, index_name)
218
+ unless index_name_exists?(table_name, index_name)
199
219
  if options.is_a?(Hash) && options.has_key?(:name)
200
220
  options_without_column = options.dup
201
221
  options_without_column.delete :column
202
- index_name_without_column = connection.index_name(table_name, options_without_column)
222
+ index_name_without_column = index_name(table_name, options_without_column)
203
223
 
204
- if connection.index_name_exists?(table_name, index_name_without_column)
205
- return index_name_without_column
206
- end
224
+ return index_name_without_column if index_name_exists?(table_name, index_name_without_column)
207
225
  end
208
226
 
209
227
  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
@@ -102,6 +102,21 @@ module ActiveRecord
102
102
  # If true, the default table name for a Product class will be "products". If false, it would just be "product".
103
103
  # See table_name for the full rules on table/class naming. This is true, by default.
104
104
 
105
+ ##
106
+ # :singleton-method: implicit_order_column
107
+ # :call-seq: implicit_order_column
108
+ #
109
+ # The name of the column records are ordered by if no explicit order clause
110
+ # is used during an ordered finder call. If not set the primary key is used.
111
+
112
+ ##
113
+ # :singleton-method: implicit_order_column=
114
+ # :call-seq: implicit_order_column=(column_name)
115
+ #
116
+ # Sets the column to sort records by when no explicit order clause is used
117
+ # during an ordered finder call. Useful when the primary key is not an
118
+ # auto-incrementing integer, for example when it's a UUID. Note that using
119
+ # a non-unique column can result in non-deterministic results.
105
120
  included do
106
121
  mattr_accessor :primary_key_prefix_type, instance_writer: false
107
122
 
@@ -110,6 +125,7 @@ module ActiveRecord
110
125
  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
111
126
  class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
112
127
  class_attribute :pluralize_table_names, instance_writer: false, default: true
128
+ class_attribute :implicit_order_column, instance_accessor: false
113
129
 
114
130
  self.protected_environments = ["production"]
115
131
  self.inheritance_column = "type"
@@ -218,11 +234,11 @@ module ActiveRecord
218
234
  end
219
235
 
220
236
  def full_table_name_prefix #:nodoc:
221
- (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
237
+ (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
222
238
  end
223
239
 
224
240
  def full_table_name_suffix #:nodoc:
225
- (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
241
+ (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
226
242
  end
227
243
 
228
244
  # The array of names of environments where destructive actions should be prohibited. By default,
@@ -276,7 +292,7 @@ module ActiveRecord
276
292
  end
277
293
 
278
294
  def sequence_name
279
- if base_class == self
295
+ if base_class?
280
296
  @sequence_name ||= reset_sequence_name
281
297
  else
282
298
  (@sequence_name ||= nil) || base_class.sequence_name
@@ -388,6 +404,11 @@ module ActiveRecord
388
404
  @column_names ||= columns.map(&:name)
389
405
  end
390
406
 
407
+ def symbol_column_to_string(name_symbol) # :nodoc:
408
+ @symbol_column_to_string_name_hash ||= column_names.index_by(&:to_sym)
409
+ @symbol_column_to_string_name_hash[name_symbol]
410
+ end
411
+
391
412
  # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
392
413
  # and columns used for single table inheritance have been removed.
393
414
  def content_columns
@@ -477,6 +498,7 @@ module ActiveRecord
477
498
  def reload_schema_from_cache
478
499
  @arel_table = nil
479
500
  @column_names = nil
501
+ @symbol_column_to_string_name_hash = nil
480
502
  @attribute_types = nil
481
503
  @content_columns = nil
482
504
  @default_attributes = nil
@@ -501,19 +523,18 @@ module ActiveRecord
501
523
 
502
524
  # Computes and returns a table name according to default conventions.
503
525
  def compute_table_name
504
- base = base_class
505
- if self == base
526
+ if base_class?
506
527
  # Nested classes are prefixed with singular parent table name.
507
- if parent < Base && !parent.abstract_class?
508
- contained = parent.table_name
509
- contained = contained.singularize if parent.pluralize_table_names
528
+ if module_parent < Base && !module_parent.abstract_class?
529
+ contained = module_parent.table_name
530
+ contained = contained.singularize if module_parent.pluralize_table_names
510
531
  contained += "_"
511
532
  end
512
533
 
513
534
  "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
514
535
  else
515
536
  # STI subclasses always use their superclass' table.
516
- base.table_name
537
+ base_class.table_name
517
538
  end
518
539
  end
519
540
  end
@@ -426,7 +426,7 @@ module ActiveRecord
426
426
  existing_record.assign_attributes(assignable_attributes)
427
427
  association(association_name).initialize_attributes(existing_record)
428
428
  else
429
- method = "build_#{association_name}"
429
+ method = :"build_#{association_name}"
430
430
  if respond_to?(method)
431
431
  send(method, assignable_attributes)
432
432
  else
@@ -501,7 +501,7 @@ module ActiveRecord
501
501
 
502
502
  if attributes["id"].blank?
503
503
  unless reject_new_record?(association_name, attributes)
504
- association.build(attributes.except(*UNASSIGNABLE_KEYS))
504
+ association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
505
505
  end
506
506
  elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
507
507
  unless call_reject_if(association_name, attributes)
@@ -43,6 +43,13 @@ module ActiveRecord
43
43
  end
44
44
  end
45
45
 
46
+ # Returns +true+ if the class has +no_touching+ set, +false+ otherwise.
47
+ #
48
+ # Project.no_touching do
49
+ # Project.first.no_touching? # true
50
+ # Message.first.no_touching? # false
51
+ # end
52
+ #
46
53
  def no_touching?
47
54
  NoTouching.applied_to?(self.class)
48
55
  end
@@ -67,8 +67,7 @@ module ActiveRecord
67
67
  # how this "single-table" inheritance mapping is implemented.
68
68
  def instantiate(attributes, column_types = {}, &block)
69
69
  klass = discriminate_class_for_record(attributes)
70
- attributes = klass.attributes_builder.build_from_database(attributes, column_types)
71
- klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
70
+ instantiate_instance_of(klass, attributes, column_types, &block)
72
71
  end
73
72
 
74
73
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -178,7 +177,7 @@ module ActiveRecord
178
177
  end
179
178
 
180
179
  if values.empty?
181
- im = arel_table.compile_insert(connection.empty_insert_statement_value)
180
+ im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
182
181
  im.into arel_table
183
182
  else
184
183
  im = arel_table.compile_insert(_substitute_values(values))
@@ -208,6 +207,13 @@ module ActiveRecord
208
207
  end
209
208
 
210
209
  private
210
+ # Given a class, an attributes hash, +instantiate_instance_of+ returns a
211
+ # new instance of the class. Accepts only keys as strings.
212
+ def instantiate_instance_of(klass, attributes, column_types = {}, &block)
213
+ attributes = klass.attributes_builder.build_from_database(attributes, column_types)
214
+ klass.allocate.init_with_attributes(attributes, &block)
215
+ end
216
+
211
217
  # Called by +instantiate+ to decide which class to use for a new
212
218
  # record instance.
213
219
  #
@@ -430,6 +436,7 @@ module ActiveRecord
430
436
  end
431
437
 
432
438
  alias update_attributes update
439
+ deprecate :update_attributes
433
440
 
434
441
  # Updates its receiver just like #update but calls #save! instead
435
442
  # of +save+, so an exception is raised if the record is invalid and saving will fail.
@@ -443,6 +450,7 @@ module ActiveRecord
443
450
  end
444
451
 
445
452
  alias update_attributes! update!
453
+ deprecate :update_attributes!
446
454
 
447
455
  # Equivalent to <code>update_columns(name => value)</code>.
448
456
  def update_column(name, value)
@@ -709,7 +717,6 @@ module ActiveRecord
709
717
  # Updates the associated record with values matching those of the instance attributes.
710
718
  # Returns the number of affected rows.
711
719
  def _update_record(attribute_names = self.attribute_names)
712
- attribute_names &= self.class.column_names
713
720
  attribute_names = attributes_for_update(attribute_names)
714
721
 
715
722
  if attribute_names.empty?
@@ -728,10 +735,12 @@ module ActiveRecord
728
735
  # Creates a record with values matching those of the instance attributes
729
736
  # and returns its id.
730
737
  def _create_record(attribute_names = self.attribute_names)
731
- attribute_names &= self.class.column_names
732
- attributes_values = attributes_with_values_for_create(attribute_names)
738
+ attribute_names = attributes_for_create(attribute_names)
739
+
740
+ new_id = self.class._insert_record(
741
+ attributes_with_values(attribute_names)
742
+ )
733
743
 
734
- new_id = self.class._insert_record(attributes_values)
735
744
  self.id ||= new_id if self.class.primary_key
736
745
 
737
746
  @new_record = false
@@ -752,6 +761,8 @@ module ActiveRecord
752
761
  @_association_destroy_exception = nil
753
762
  end
754
763
 
764
+ # The name of the method used to touch a +belongs_to+ association when the
765
+ # +:touch+ option is used.
755
766
  def belongs_to_touch_method
756
767
  :touch
757
768
  end
@@ -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
 
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
6
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
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
8
+ delegate :find_or_create_by, :find_or_create_by!, :create_or_find_by, :create_or_find_by!, :find_or_initialize_by, to: :all
9
9
  delegate :find_by, :find_by!, to: :all
10
10
  delegate :destroy_all, :delete_all, :update_all, to: :all
11
11
  delegate :find_each, :find_in_batches, :in_batches, to: :all
@@ -13,20 +13,20 @@ module ActiveRecord
13
13
  :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
14
14
  :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
15
15
  delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
16
- delegate :pluck, :ids, to: :all
16
+ delegate :pluck, :pick, :ids, to: :all
17
17
 
18
18
  # 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
19
+ # be returned as an array, with the requested columns encapsulated as attributes of the model you call
20
+ # this method from. For example, if you call <tt>Product.find_by_sql</tt>, then the results will be returned in
21
21
  # a +Product+ object with the attributes you specified in the SQL query.
22
22
  #
23
- # If you call a complicated SQL query which spans multiple tables the columns specified by the
23
+ # If you call a complicated SQL query which spans multiple tables, the columns specified by the
24
24
  # SELECT will be attributes of the model, whether or not they are columns of the corresponding
25
25
  # table.
26
26
  #
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
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
29
+ # database-specific terms will lock you into using that particular database engine, or require you to
30
30
  # change your call if you switch engines.
31
31
  #
32
32
  # # A simple SQL query spanning multiple tables
@@ -40,7 +40,8 @@ module ActiveRecord
40
40
  def find_by_sql(sql, binds = [], preparable: nil, &block)
41
41
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
42
42
  column_types = result_set.column_types.dup
43
- attribute_types.each_key { |k| column_types.delete k }
43
+ cached_columns_hash = connection.schema_cache.columns_hash(table_name)
44
+ cached_columns_hash.each_key { |k| column_types.delete k }
44
45
  message_bus = ActiveSupport::Notifications.instrumenter
45
46
 
46
47
  payload = {
@@ -49,13 +50,20 @@ module ActiveRecord
49
50
  }
50
51
 
51
52
  message_bus.instrument("instantiation.active_record", payload) do
52
- result_set.map { |record| instantiate(record, column_types, &block) }
53
+ if result_set.includes_column?(inheritance_column)
54
+ result_set.map { |record| instantiate(record, column_types, &block) }
55
+ else
56
+ # Instantiate a homogeneous set
57
+ result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
58
+ end
53
59
  end
54
60
  end
55
61
 
56
62
  # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
57
63
  # 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.
64
+ # using the ActiveRecord::Calculations class methods. Look into those before using this method,
65
+ # as it could lock you into a specific database engine or require a code change to switch
66
+ # database engines.
59
67
  #
60
68
  # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
61
69
  # # => 12