activerecord 5.2.8.1 → 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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -816
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +4 -2
  7. data/lib/active_record/associations/association.rb +35 -19
  8. data/lib/active_record/associations/association_scope.rb +4 -6
  9. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  11. data/lib/active_record/associations/builder/belongs_to.rb +14 -50
  12. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  14. data/lib/active_record/associations/collection_association.rb +11 -25
  15. data/lib/active_record/associations/collection_proxy.rb +32 -6
  16. data/lib/active_record/associations/foreign_association.rb +7 -0
  17. data/lib/active_record/associations/has_many_association.rb +1 -1
  18. data/lib/active_record/associations/has_many_through_association.rb +25 -18
  19. data/lib/active_record/associations/has_one_association.rb +28 -30
  20. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  21. data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
  22. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  23. data/lib/active_record/associations/join_dependency.rb +15 -20
  24. data/lib/active_record/associations/preloader/association.rb +1 -2
  25. data/lib/active_record/associations/preloader.rb +32 -29
  26. data/lib/active_record/associations/singular_association.rb +2 -16
  27. data/lib/active_record/associations.rb +16 -12
  28. data/lib/active_record/attribute_assignment.rb +7 -10
  29. data/lib/active_record/attribute_methods/dirty.rb +64 -26
  30. data/lib/active_record/attribute_methods/primary_key.rb +8 -7
  31. data/lib/active_record/attribute_methods/read.rb +16 -48
  32. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  33. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  34. data/lib/active_record/attribute_methods/write.rb +15 -16
  35. data/lib/active_record/attribute_methods.rb +34 -56
  36. data/lib/active_record/autosave_association.rb +7 -21
  37. data/lib/active_record/base.rb +2 -2
  38. data/lib/active_record/callbacks.rb +3 -17
  39. data/lib/active_record/coders/yaml_column.rb +1 -13
  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/money.rb +2 -2
  67. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  68. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  69. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  70. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
  71. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
  73. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
  74. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
  75. data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
  76. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
  77. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
  78. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
  79. data/lib/active_record/connection_handling.rb +132 -26
  80. data/lib/active_record/core.rb +75 -52
  81. data/lib/active_record/counter_cache.rb +4 -29
  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/database_configurations.rb +184 -0
  86. data/lib/active_record/enum.rb +22 -7
  87. data/lib/active_record/errors.rb +24 -21
  88. data/lib/active_record/explain.rb +1 -1
  89. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  90. data/lib/active_record/fixture_set/render_context.rb +17 -0
  91. data/lib/active_record/fixture_set/table_row.rb +153 -0
  92. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  93. data/lib/active_record/fixtures.rb +140 -472
  94. data/lib/active_record/gem_version.rb +4 -4
  95. data/lib/active_record/inheritance.rb +12 -2
  96. data/lib/active_record/integration.rb +56 -16
  97. data/lib/active_record/internal_metadata.rb +5 -1
  98. data/lib/active_record/locking/optimistic.rb +2 -2
  99. data/lib/active_record/locking/pessimistic.rb +3 -3
  100. data/lib/active_record/log_subscriber.rb +7 -26
  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/migration.rb +38 -37
  104. data/lib/active_record/model_schema.rb +30 -9
  105. data/lib/active_record/nested_attributes.rb +2 -2
  106. data/lib/active_record/no_touching.rb +7 -0
  107. data/lib/active_record/persistence.rb +18 -7
  108. data/lib/active_record/query_cache.rb +11 -4
  109. data/lib/active_record/querying.rb +19 -11
  110. data/lib/active_record/railtie.rb +71 -60
  111. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  112. data/lib/active_record/railties/controller_runtime.rb +30 -35
  113. data/lib/active_record/railties/databases.rake +94 -43
  114. data/lib/active_record/reflection.rb +60 -44
  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/array_handler.rb +5 -4
  121. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  122. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  123. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  124. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  125. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  126. data/lib/active_record/relation/predicate_builder.rb +4 -6
  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/relation.rb +150 -69
  132. data/lib/active_record/result.rb +30 -11
  133. data/lib/active_record/sanitization.rb +2 -39
  134. data/lib/active_record/schema.rb +1 -10
  135. data/lib/active_record/schema_dumper.rb +12 -6
  136. data/lib/active_record/schema_migration.rb +4 -0
  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/scoping.rb +9 -8
  140. data/lib/active_record/statement_cache.rb +32 -5
  141. data/lib/active_record/store.rb +39 -8
  142. data/lib/active_record/table_metadata.rb +1 -4
  143. data/lib/active_record/tasks/database_tasks.rb +89 -23
  144. data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
  145. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  146. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  147. data/lib/active_record/test_databases.rb +38 -0
  148. data/lib/active_record/test_fixtures.rb +224 -0
  149. data/lib/active_record/timestamp.rb +4 -6
  150. data/lib/active_record/transactions.rb +3 -22
  151. data/lib/active_record/translation.rb +1 -1
  152. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  153. data/lib/active_record/type.rb +3 -4
  154. data/lib/active_record/type_caster/connection.rb +1 -6
  155. data/lib/active_record/type_caster/map.rb +1 -4
  156. data/lib/active_record/validations/uniqueness.rb +13 -25
  157. data/lib/active_record.rb +2 -1
  158. data/lib/arel/alias_predication.rb +9 -0
  159. data/lib/arel/attributes/attribute.rb +37 -0
  160. data/lib/arel/attributes.rb +22 -0
  161. data/lib/arel/collectors/bind.rb +24 -0
  162. data/lib/arel/collectors/composite.rb +31 -0
  163. data/lib/arel/collectors/plain_string.rb +20 -0
  164. data/lib/arel/collectors/sql_string.rb +20 -0
  165. data/lib/arel/collectors/substitute_binds.rb +28 -0
  166. data/lib/arel/crud.rb +42 -0
  167. data/lib/arel/delete_manager.rb +18 -0
  168. data/lib/arel/errors.rb +9 -0
  169. data/lib/arel/expressions.rb +29 -0
  170. data/lib/arel/factory_methods.rb +49 -0
  171. data/lib/arel/insert_manager.rb +49 -0
  172. data/lib/arel/math.rb +45 -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/nodes.rb +67 -0
  217. data/lib/arel/order_predications.rb +13 -0
  218. data/lib/arel/predications.rb +257 -0
  219. data/lib/arel/select_manager.rb +271 -0
  220. data/lib/arel/table.rb +110 -0
  221. data/lib/arel/tree_manager.rb +72 -0
  222. data/lib/arel/update_manager.rb +34 -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/visitors.rb +20 -0
  237. data/lib/arel/window_predications.rb +9 -0
  238. data/lib/arel.rb +44 -0
  239. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  240. data/lib/rails/generators/active_record/migration.rb +14 -1
  241. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  242. metadata +107 -29
@@ -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
@@ -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,31 @@ module ActiveRecord
84
88
  end
85
89
  end
86
90
 
91
+ initializer "Check for cache versioning support" do
92
+ config.after_initialize do |app|
93
+ ActiveSupport.on_load(:active_record) do
94
+ if app.config.active_record.cache_versioning && Rails.cache
95
+ unless Rails.cache.class.try(:supports_cache_versioning?)
96
+ raise <<-end_error
97
+
98
+ You're using a cache store that doesn't support native cache versioning.
99
+ Your best option is to upgrade to a newer version of #{Rails.cache.class}
100
+ that supports cache versioning (#{Rails.cache.class}.supports_cache_versioning? #=> true).
101
+
102
+ Next best, switch to a different cache store that does support cache versioning:
103
+ https://guides.rubyonrails.org/caching_with_rails.html#cache-stores.
104
+
105
+ To keep using the current cache store, you can turn off cache versioning entirely:
106
+
107
+ config.active_record.cache_versioning = false
108
+
109
+ end_error
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+
87
116
  initializer "active_record.check_schema_cache_dump" do
88
117
  if config.active_record.delete(:use_schema_cache_dump)
89
118
  config.after_initialize do |app|
@@ -108,6 +137,26 @@ module ActiveRecord
108
137
  end
109
138
  end
110
139
 
140
+ initializer "active_record.define_attribute_methods" do |app|
141
+ config.after_initialize do
142
+ ActiveSupport.on_load(:active_record) do
143
+ if app.config.eager_load
144
+ descendants.each do |model|
145
+ # SchemaMigration and InternalMetadata both override `table_exists?`
146
+ # to bypass the schema cache, so skip them to avoid the extra queries.
147
+ next if model._internal?
148
+
149
+ # If there's no connection yet, or the schema cache doesn't have the columns
150
+ # hash for the model cached, `define_attribute_methods` would trigger a query.
151
+ next unless model.connected? && model.connection.schema_cache.columns_hash?(model.table_name)
152
+
153
+ model.define_attribute_methods
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
111
160
  initializer "active_record.warn_on_records_fetched_greater_than" do
112
161
  if config.active_record.warn_on_records_fetched_greater_than
113
162
  ActiveSupport.on_load(:active_record) do
@@ -118,8 +167,18 @@ module ActiveRecord
118
167
 
119
168
  initializer "active_record.set_configs" do |app|
120
169
  ActiveSupport.on_load(:active_record) do
121
- configs = app.config.active_record.dup
170
+ configs = app.config.active_record
171
+
172
+ represent_boolean_as_integer = configs.sqlite3.delete(:represent_boolean_as_integer)
173
+
174
+ unless represent_boolean_as_integer.nil?
175
+ ActiveSupport.on_load(:active_record_sqlite3adapter) do
176
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
177
+ end
178
+ end
179
+
122
180
  configs.delete(:sqlite3)
181
+
123
182
  configs.each do |k, v|
124
183
  send "#{k}=", v
125
184
  end
@@ -131,21 +190,7 @@ module ActiveRecord
131
190
  initializer "active_record.initialize_database" do
132
191
  ActiveSupport.on_load(:active_record) do
133
192
  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
193
+ establish_connection
149
194
  end
150
195
  end
151
196
 
@@ -157,6 +202,13 @@ end_warning
157
202
  end
158
203
  end
159
204
 
205
+ initializer "active_record.collection_cache_association_loading" do
206
+ require "active_record/railties/collection_cache_association_loading"
207
+ ActiveSupport.on_load(:action_view) do
208
+ ActionView::PartialRenderer.prepend(ActiveRecord::Railties::CollectionCacheAssociationLoading)
209
+ end
210
+ end
211
+
160
212
  initializer "active_record.set_reloader_hooks" do
161
213
  ActiveSupport.on_load(:active_record) do
162
214
  ActiveSupport::Reloader.before_class_unload do
@@ -194,50 +246,9 @@ end_warning
194
246
  end
195
247
  end
196
248
 
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
223
- end
224
- end
225
-
226
- initializer "active_record.use_yaml_unsafe_load" do |app|
227
- config.after_initialize do
228
- unless app.config.active_record.use_yaml_unsafe_load.nil?
229
- ActiveRecord::Base.use_yaml_unsafe_load =
230
- app.config.active_record.use_yaml_unsafe_load
231
- end
232
- end
233
- end
234
-
235
- initializer "active_record.yaml_column_permitted_classes" do |app|
236
- config.after_initialize do
237
- unless app.config.active_record.yaml_column_permitted_classes.nil?
238
- ActiveRecord::Base.yaml_column_permitted_classes =
239
- app.config.active_record.yaml_column_permitted_classes
240
- end
249
+ initializer "active_record.set_filter_attributes" do
250
+ ActiveSupport.on_load(:active_record) do
251
+ self.filter_attributes += Rails.application.config.filter_parameters
241
252
  end
242
253
  end
243
254
  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, 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