activerecord 6.1.3.2 → 7.0.0.alpha2

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +734 -1058
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +35 -7
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +16 -6
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +24 -25
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -49
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +11 -1
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  66. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  67. data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  69. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  72. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  76. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  77. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
  78. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  79. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  80. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  81. data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
  82. data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
  83. data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
  84. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
  85. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  86. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  87. data/lib/active_record/connection_adapters.rb +8 -5
  88. data/lib/active_record/connection_handling.rb +20 -38
  89. data/lib/active_record/core.rb +129 -117
  90. data/lib/active_record/database_configurations/database_config.rb +12 -0
  91. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  92. data/lib/active_record/database_configurations/url_config.rb +2 -2
  93. data/lib/active_record/database_configurations.rb +18 -9
  94. data/lib/active_record/delegated_type.rb +33 -11
  95. data/lib/active_record/destroy_association_async_job.rb +1 -1
  96. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  97. data/lib/active_record/dynamic_matchers.rb +1 -1
  98. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  99. data/lib/active_record/encryption/cipher.rb +53 -0
  100. data/lib/active_record/encryption/config.rb +44 -0
  101. data/lib/active_record/encryption/configurable.rb +61 -0
  102. data/lib/active_record/encryption/context.rb +35 -0
  103. data/lib/active_record/encryption/contexts.rb +72 -0
  104. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  105. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  106. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  107. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  108. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  109. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  110. data/lib/active_record/encryption/encryptor.rb +155 -0
  111. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  112. data/lib/active_record/encryption/errors.rb +15 -0
  113. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  114. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  115. data/lib/active_record/encryption/key.rb +28 -0
  116. data/lib/active_record/encryption/key_generator.rb +42 -0
  117. data/lib/active_record/encryption/key_provider.rb +46 -0
  118. data/lib/active_record/encryption/message.rb +33 -0
  119. data/lib/active_record/encryption/message_serializer.rb +80 -0
  120. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  121. data/lib/active_record/encryption/properties.rb +76 -0
  122. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  123. data/lib/active_record/encryption/scheme.rb +99 -0
  124. data/lib/active_record/encryption.rb +55 -0
  125. data/lib/active_record/enum.rb +44 -46
  126. data/lib/active_record/errors.rb +66 -3
  127. data/lib/active_record/fixture_set/file.rb +15 -1
  128. data/lib/active_record/fixture_set/table_row.rb +40 -5
  129. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  130. data/lib/active_record/fixtures.rb +16 -11
  131. data/lib/active_record/future_result.rb +139 -0
  132. data/lib/active_record/gem_version.rb +4 -4
  133. data/lib/active_record/inheritance.rb +55 -17
  134. data/lib/active_record/insert_all.rb +39 -6
  135. data/lib/active_record/integration.rb +1 -1
  136. data/lib/active_record/internal_metadata.rb +3 -5
  137. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  138. data/lib/active_record/locking/optimistic.rb +10 -9
  139. data/lib/active_record/log_subscriber.rb +6 -2
  140. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  141. data/lib/active_record/middleware/database_selector.rb +8 -3
  142. data/lib/active_record/migration/command_recorder.rb +4 -4
  143. data/lib/active_record/migration/compatibility.rb +83 -1
  144. data/lib/active_record/migration/join_table.rb +1 -1
  145. data/lib/active_record/migration.rb +109 -79
  146. data/lib/active_record/model_schema.rb +46 -32
  147. data/lib/active_record/nested_attributes.rb +3 -3
  148. data/lib/active_record/no_touching.rb +2 -2
  149. data/lib/active_record/null_relation.rb +2 -6
  150. data/lib/active_record/persistence.rb +134 -45
  151. data/lib/active_record/query_cache.rb +2 -2
  152. data/lib/active_record/query_logs.rb +203 -0
  153. data/lib/active_record/querying.rb +15 -5
  154. data/lib/active_record/railtie.rb +117 -17
  155. data/lib/active_record/railties/controller_runtime.rb +1 -1
  156. data/lib/active_record/railties/databases.rake +83 -58
  157. data/lib/active_record/readonly_attributes.rb +11 -0
  158. data/lib/active_record/reflection.rb +45 -44
  159. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  160. data/lib/active_record/relation/batches.rb +3 -3
  161. data/lib/active_record/relation/calculations.rb +42 -25
  162. data/lib/active_record/relation/delegation.rb +6 -6
  163. data/lib/active_record/relation/finder_methods.rb +32 -23
  164. data/lib/active_record/relation/merger.rb +20 -13
  165. data/lib/active_record/relation/predicate_builder.rb +1 -6
  166. data/lib/active_record/relation/query_attribute.rb +5 -11
  167. data/lib/active_record/relation/query_methods.rb +233 -50
  168. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  169. data/lib/active_record/relation/spawn_methods.rb +2 -2
  170. data/lib/active_record/relation/where_clause.rb +22 -15
  171. data/lib/active_record/relation.rb +170 -87
  172. data/lib/active_record/result.rb +17 -2
  173. data/lib/active_record/runtime_registry.rb +2 -4
  174. data/lib/active_record/sanitization.rb +11 -7
  175. data/lib/active_record/schema_dumper.rb +3 -3
  176. data/lib/active_record/schema_migration.rb +0 -4
  177. data/lib/active_record/scoping/default.rb +62 -15
  178. data/lib/active_record/scoping/named.rb +3 -11
  179. data/lib/active_record/scoping.rb +40 -22
  180. data/lib/active_record/serialization.rb +1 -1
  181. data/lib/active_record/signed_id.rb +1 -1
  182. data/lib/active_record/statement_cache.rb +2 -2
  183. data/lib/active_record/tasks/database_tasks.rb +107 -23
  184. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  185. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  186. data/lib/active_record/test_databases.rb +1 -1
  187. data/lib/active_record/test_fixtures.rb +45 -4
  188. data/lib/active_record/timestamp.rb +3 -4
  189. data/lib/active_record/transactions.rb +9 -14
  190. data/lib/active_record/translation.rb +2 -2
  191. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  192. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  193. data/lib/active_record/type/internal/timezone.rb +2 -2
  194. data/lib/active_record/type/serialized.rb +1 -1
  195. data/lib/active_record/type/type_map.rb +17 -20
  196. data/lib/active_record/type.rb +1 -2
  197. data/lib/active_record/validations/associated.rb +1 -1
  198. data/lib/active_record/validations/numericality.rb +1 -1
  199. data/lib/active_record.rb +170 -2
  200. data/lib/arel/attributes/attribute.rb +0 -8
  201. data/lib/arel/collectors/bind.rb +2 -2
  202. data/lib/arel/collectors/composite.rb +3 -3
  203. data/lib/arel/collectors/sql_string.rb +1 -1
  204. data/lib/arel/collectors/substitute_binds.rb +1 -1
  205. data/lib/arel/crud.rb +18 -22
  206. data/lib/arel/delete_manager.rb +2 -4
  207. data/lib/arel/insert_manager.rb +2 -3
  208. data/lib/arel/nodes/casted.rb +1 -1
  209. data/lib/arel/nodes/delete_statement.rb +8 -13
  210. data/lib/arel/nodes/homogeneous_in.rb +4 -0
  211. data/lib/arel/nodes/insert_statement.rb +2 -2
  212. data/lib/arel/nodes/select_core.rb +2 -2
  213. data/lib/arel/nodes/select_statement.rb +2 -2
  214. data/lib/arel/nodes/update_statement.rb +3 -2
  215. data/lib/arel/predications.rb +3 -3
  216. data/lib/arel/select_manager.rb +10 -4
  217. data/lib/arel/table.rb +0 -1
  218. data/lib/arel/tree_manager.rb +0 -12
  219. data/lib/arel/update_manager.rb +2 -4
  220. data/lib/arel/visitors/dot.rb +80 -90
  221. data/lib/arel/visitors/mysql.rb +6 -1
  222. data/lib/arel/visitors/postgresql.rb +0 -10
  223. data/lib/arel/visitors/to_sql.rb +44 -3
  224. data/lib/arel.rb +1 -1
  225. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  227. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  228. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  229. metadata +55 -16
@@ -127,8 +127,7 @@ module ActiveRecord
127
127
  # <tt>attribute :foo, :string</tt>. Defaults to false.
128
128
 
129
129
  included do
130
- mattr_accessor :primary_key_prefix_type, instance_writer: false
131
-
130
+ class_attribute :primary_key_prefix_type, instance_writer: false
132
131
  class_attribute :table_name_prefix, instance_writer: false, default: ""
133
132
  class_attribute :table_name_suffix, instance_writer: false, default: ""
134
133
  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
@@ -137,8 +136,24 @@ module ActiveRecord
137
136
  class_attribute :implicit_order_column, instance_accessor: false
138
137
  class_attribute :immutable_strings_by_default, instance_accessor: false
139
138
 
139
+ # Defines the name of the table column which will store the class name on single-table
140
+ # inheritance situations.
141
+ #
142
+ # The default inheritance column name is +type+, which means it's a
143
+ # reserved word inside Active Record. To be able to use single-table
144
+ # inheritance with another column name, or to use the column +type+ in
145
+ # your own model for something else, you can set +inheritance_column+:
146
+ #
147
+ # self.inheritance_column = 'zoink'
148
+ class_attribute :inheritance_column, instance_accessor: false, default: "type"
149
+ singleton_class.class_eval do
150
+ alias_method :_inheritance_column=, :inheritance_column=
151
+ private :_inheritance_column=
152
+ alias_method :inheritance_column=, :real_inheritance_column=
153
+ end
154
+
140
155
  self.protected_environments = ["production"]
141
- self.inheritance_column = "type"
156
+
142
157
  self.ignored_columns = [].freeze
143
158
 
144
159
  delegate :type_for_attribute, :column_for_attribute, to: :class
@@ -197,6 +212,21 @@ module ActiveRecord
197
212
  # the table name guess for an Invoice class becomes "myapp_invoices".
198
213
  # Invoice::Lineitem becomes "myapp_invoice_lineitems".
199
214
  #
215
+ # Active Model Naming's +model_name+ is the base name used to guess the
216
+ # table name. In case a custom Active Model Name is defined, it will be
217
+ # used for the table name as well:
218
+ #
219
+ # class PostRecord < ActiveRecord::Base
220
+ # class << self
221
+ # def model_name
222
+ # ActiveModel::Name.new(self, nil, "Post")
223
+ # end
224
+ # end
225
+ # end
226
+ #
227
+ # PostRecord.table_name
228
+ # # => "posts"
229
+ #
200
230
  # You can also set your own table name explicitly:
201
231
  #
202
232
  # class Mouse < ActiveRecord::Base
@@ -233,7 +263,7 @@ module ActiveRecord
233
263
  end
234
264
 
235
265
  # Computes the table name, (re)sets it internally, and returns it.
236
- def reset_table_name #:nodoc:
266
+ def reset_table_name # :nodoc:
237
267
  self.table_name = if abstract_class?
238
268
  superclass == Base ? nil : superclass.table_name
239
269
  elsif superclass.abstract_class?
@@ -243,11 +273,11 @@ module ActiveRecord
243
273
  end
244
274
  end
245
275
 
246
- def full_table_name_prefix #:nodoc:
276
+ def full_table_name_prefix # :nodoc:
247
277
  (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
248
278
  end
249
279
 
250
- def full_table_name_suffix #:nodoc:
280
+ def full_table_name_suffix # :nodoc:
251
281
  (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
252
282
  end
253
283
 
@@ -266,23 +296,8 @@ module ActiveRecord
266
296
  @protected_environments = environments.map(&:to_s)
267
297
  end
268
298
 
269
- # Defines the name of the table column which will store the class name on single-table
270
- # inheritance situations.
271
- #
272
- # The default inheritance column name is +type+, which means it's a
273
- # reserved word inside Active Record. To be able to use single-table
274
- # inheritance with another column name, or to use the column +type+ in
275
- # your own model for something else, you can set +inheritance_column+:
276
- #
277
- # self.inheritance_column = 'zoink'
278
- def inheritance_column
279
- (@inheritance_column ||= nil) || superclass.inheritance_column
280
- end
281
-
282
- # Sets the value of inheritance_column
283
- def inheritance_column=(value)
284
- @inheritance_column = value.to_s
285
- @explicit_inheritance_column = true
299
+ def real_inheritance_column=(value) # :nodoc:
300
+ self._inheritance_column = value.to_s
286
301
  end
287
302
 
288
303
  # The list of columns names the model should ignore. Ignored columns won't have attribute
@@ -339,7 +354,7 @@ module ActiveRecord
339
354
  end
340
355
  end
341
356
 
342
- def reset_sequence_name #:nodoc:
357
+ def reset_sequence_name # :nodoc:
343
358
  @explicit_sequence_name = false
344
359
  @sequence_name = connection.default_sequence_name(table_name, primary_key)
345
360
  end
@@ -486,9 +501,9 @@ module ActiveRecord
486
501
  #
487
502
  # The most common usage pattern for this method is probably in a migration,
488
503
  # when just after creating a table you want to populate it with some default
489
- # values, eg:
504
+ # values, e.g.:
490
505
  #
491
- # class CreateJobLevels < ActiveRecord::Migration[6.0]
506
+ # class CreateJobLevels < ActiveRecord::Migration[7.0]
492
507
  # def up
493
508
  # create_table :job_levels do |t|
494
509
  # t.integer :id
@@ -574,7 +589,6 @@ module ActiveRecord
574
589
  @content_columns = nil
575
590
  @default_attributes = nil
576
591
  @column_defaults = nil
577
- @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
578
592
  @attributes_builder = nil
579
593
  @columns = nil
580
594
  @columns_hash = nil
@@ -587,8 +601,8 @@ module ActiveRecord
587
601
  end
588
602
 
589
603
  # Guesses the table name, but does not decorate it with prefix and suffix information.
590
- def undecorated_table_name(class_name = base_class.name)
591
- table_name = class_name.to_s.demodulize.underscore
604
+ def undecorated_table_name(model_name)
605
+ table_name = model_name.to_s.demodulize.underscore
592
606
  pluralize_table_names ? table_name.pluralize : table_name
593
607
  end
594
608
 
@@ -602,7 +616,7 @@ module ActiveRecord
602
616
  contained += "_"
603
617
  end
604
618
 
605
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
619
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
606
620
  else
607
621
  # STI subclasses always use their superclass' table.
608
622
  base_class.table_name
@@ -619,7 +633,7 @@ module ActiveRecord
619
633
 
620
634
  def warn_if_deprecated_type(column)
621
635
  return if attributes_to_define_after_schema_loads.key?(column.name)
622
- return unless column.respond_to?(:oid)
636
+ return unless column.respond_to?(:array?)
623
637
 
624
638
  if column.array?
625
639
  array_arguments = ", array: true"
@@ -630,7 +644,7 @@ module ActiveRecord
630
644
  if column.sql_type.start_with?("interval")
631
645
  precision_arguments = column.precision.presence && ", precision: #{column.precision}"
632
646
  ActiveSupport::Deprecation.warn(<<~WARNING)
633
- The behavior of the `:interval` type will be changing in Rails 6.2
647
+ The behavior of the `:interval` type will be changing in Rails 7.0
634
648
  to return an `ActiveSupport::Duration` object. If you'd like to keep
635
649
  the old behavior, you can add this line to #{self.name} model:
636
650
 
@@ -5,7 +5,7 @@ require "active_support/core_ext/module/redefine_method"
5
5
  require "active_support/core_ext/hash/indifferent_access"
6
6
 
7
7
  module ActiveRecord
8
- module NestedAttributes #:nodoc:
8
+ module NestedAttributes # :nodoc:
9
9
  class TooManyRecords < ActiveRecordError
10
10
  end
11
11
 
@@ -180,7 +180,7 @@ module ActiveRecord
180
180
  # member.posts.second.title # => '[UPDATED] other post'
181
181
  #
182
182
  # However, the above applies if the parent model is being updated as well.
183
- # For example, If you wanted to create a +member+ named _joe_ and wanted to
183
+ # For example, if you wanted to create a +member+ named _joe_ and wanted to
184
184
  # update the +posts+ at the same time, that would give an
185
185
  # ActiveRecord::RecordNotFound error.
186
186
  #
@@ -486,7 +486,7 @@ module ActiveRecord
486
486
  existing_records = if association.loaded?
487
487
  association.target
488
488
  else
489
- attribute_ids = attributes_collection.map { |a| a["id"] || a[:id] }.compact
489
+ attribute_ids = attributes_collection.filter_map { |a| a["id"] || a[:id] }
490
490
  attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
491
491
  end
492
492
 
@@ -26,14 +26,14 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  class << self
29
- def apply_to(klass) #:nodoc:
29
+ def apply_to(klass) # :nodoc:
30
30
  klasses.push(klass)
31
31
  yield
32
32
  ensure
33
33
  klasses.pop
34
34
  end
35
35
 
36
- def applied_to?(klass) #:nodoc:
36
+ def applied_to?(klass) # :nodoc:
37
37
  klasses.any? { |k| k >= klass }
38
38
  end
39
39
 
@@ -38,10 +38,6 @@ module ActiveRecord
38
38
  false
39
39
  end
40
40
 
41
- def to_sql
42
- ""
43
- end
44
-
45
41
  def calculate(operation, _column_name)
46
42
  case operation
47
43
  when :count, :sum
@@ -60,8 +56,8 @@ module ActiveRecord
60
56
  end
61
57
 
62
58
  private
63
- def exec_queries
64
- @records = [].freeze
59
+ def exec_main_query(async: false)
60
+ [].freeze
65
61
  end
66
62
  end
67
63
  end
@@ -91,6 +91,9 @@ module ActiveRecord
91
91
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
92
92
  # clause entirely.
93
93
  #
94
+ # You can also pass an SQL string if you need more control on the return values
95
+ # (for example, <tt>returning: "id, name as new_name"</tt>).
96
+ #
94
97
  # [:unique_by]
95
98
  # (PostgreSQL and SQLite only) By default rows are considered to be unique
96
99
  # by every unique index on the table. Any duplicate rows are skipped.
@@ -120,6 +123,14 @@ module ActiveRecord
120
123
  # { id: 1, title: "Rework", author: "David" },
121
124
  # { id: 1, title: "Eloquent Ruby", author: "Russ" }
122
125
  # ])
126
+ #
127
+ # # insert_all works on chained scopes, and you can use create_with
128
+ # # to set default attributes for all inserted records.
129
+ #
130
+ # author.books.create_with(created_at: Time.now).insert_all([
131
+ # { id: 1, title: "Rework" },
132
+ # { id: 2, title: "Eloquent Ruby" }
133
+ # ])
123
134
  def insert_all(attributes, returning: nil, unique_by: nil)
124
135
  InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
125
136
  end
@@ -160,6 +171,9 @@ module ActiveRecord
160
171
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
161
172
  # clause entirely.
162
173
  #
174
+ # You can also pass an SQL string if you need more control on the return values
175
+ # (for example, <tt>returning: "id, name as new_name"</tt>).
176
+ #
163
177
  # ==== Examples
164
178
  #
165
179
  # # Insert multiple records
@@ -184,8 +198,8 @@ module ActiveRecord
184
198
  # go through Active Record's type casting and serialization.
185
199
  #
186
200
  # See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
187
- def upsert(attributes, returning: nil, unique_by: nil)
188
- upsert_all([ attributes ], returning: returning, unique_by: unique_by)
201
+ def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil)
202
+ upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by)
189
203
  end
190
204
 
191
205
  # Updates or inserts (upserts) multiple records into the database in a
@@ -208,6 +222,9 @@ module ActiveRecord
208
222
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
209
223
  # clause entirely.
210
224
  #
225
+ # You can also pass an SQL string if you need more control on the return values
226
+ # (for example, <tt>returning: "id, name as new_name"</tt>).
227
+ #
211
228
  # [:unique_by]
212
229
  # (PostgreSQL and SQLite only) By default rows are considered to be unique
213
230
  # by every unique index on the table. Any duplicate rows are skipped.
@@ -228,6 +245,11 @@ module ActiveRecord
228
245
  # <tt>:unique_by</tt> is recommended to be paired with
229
246
  # Active Record's schema_cache.
230
247
  #
248
+ # [:on_duplicate]
249
+ # Specify a custom SQL for updating rows on conflict.
250
+ #
251
+ # NOTE: in this case you must provide all the columns you want to update by yourself.
252
+ #
231
253
  # ==== Examples
232
254
  #
233
255
  # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
@@ -239,8 +261,8 @@ module ActiveRecord
239
261
  # ], unique_by: :isbn)
240
262
  #
241
263
  # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
242
- def upsert_all(attributes, returning: nil, unique_by: nil)
243
- InsertAll.new(self, attributes, on_duplicate: :update, returning: returning, unique_by: unique_by).execute
264
+ def upsert_all(attributes, on_duplicate: :update, returning: nil, unique_by: nil)
265
+ InsertAll.new(self, attributes, on_duplicate: on_duplicate, returning: returning, unique_by: unique_by).execute
244
266
  end
245
267
 
246
268
  # Given an attributes hash, +instantiate+ returns a new instance of
@@ -264,6 +286,7 @@ module ActiveRecord
264
286
  # ==== Parameters
265
287
  #
266
288
  # * +id+ - This should be the id or an array of ids to be updated.
289
+ # Optional argument, defaults to all records in the relation.
267
290
  # * +attributes+ - This should be a hash of attributes or an array of hashes.
268
291
  #
269
292
  # ==== Examples
@@ -286,6 +309,11 @@ module ActiveRecord
286
309
  # for updating all records in a single query.
287
310
  def update(id = :all, attributes)
288
311
  if id.is_a?(Array)
312
+ if id.any?(ActiveRecord::Base)
313
+ raise ArgumentError,
314
+ "You are passing an array of ActiveRecord::Base instances to `update`. " \
315
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
316
+ end
289
317
  id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
290
318
  object.update(attributes[idx])
291
319
  }
@@ -303,6 +331,32 @@ module ActiveRecord
303
331
  end
304
332
  end
305
333
 
334
+ # Updates the object (or multiple objects) just like #update but calls #update! instead
335
+ # of +update+, so an exception is raised if the record is invalid and saving will fail.
336
+ def update!(id = :all, attributes)
337
+ if id.is_a?(Array)
338
+ if id.any?(ActiveRecord::Base)
339
+ raise ArgumentError,
340
+ "You are passing an array of ActiveRecord::Base instances to `update!`. " \
341
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
342
+ end
343
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
344
+ object.update!(attributes[idx])
345
+ }
346
+ elsif id == :all
347
+ all.each { |record| record.update!(attributes) }
348
+ else
349
+ if ActiveRecord::Base === id
350
+ raise ArgumentError,
351
+ "You are passing an instance of ActiveRecord::Base to `update!`. " \
352
+ "Please pass the id of the object by calling `.id`."
353
+ end
354
+ object = find(id)
355
+ object.update!(attributes)
356
+ object
357
+ end
358
+ end
359
+
306
360
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
307
361
  # therefore all callbacks and filters are fired off before the object is deleted. This method is
308
362
  # less efficient than #delete but allows cleanup methods and other actions to be run.
@@ -356,40 +410,54 @@ module ActiveRecord
356
410
  primary_key = self.primary_key
357
411
  primary_key_value = nil
358
412
 
359
- if primary_key && Hash === values
360
- primary_key_value = values[primary_key]
361
-
362
- if !primary_key_value && prefetch_primary_key?
413
+ if prefetch_primary_key? && primary_key
414
+ values[primary_key] ||= begin
363
415
  primary_key_value = next_sequence_value
364
- values[primary_key] = primary_key_value
416
+ _default_attributes[primary_key].with_cast_value(primary_key_value)
365
417
  end
366
418
  end
367
419
 
420
+ im = Arel::InsertManager.new(arel_table)
421
+
368
422
  if values.empty?
369
- im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
370
- im.into arel_table
423
+ im.insert(connection.empty_insert_statement_value(primary_key))
371
424
  else
372
- im = arel_table.compile_insert(_substitute_values(values))
425
+ im.insert(values.transform_keys { |name| arel_table[name] })
373
426
  end
374
427
 
375
428
  connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
376
429
  end
377
430
 
378
431
  def _update_record(values, constraints) # :nodoc:
379
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
432
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
380
433
 
381
- um = arel_table.where(
382
- constraints.reduce(&:and)
383
- ).compile_update(_substitute_values(values), primary_key)
434
+ if default_scopes?(all_queries: true)
435
+ constraints << default_scoped(all_queries: true).where_clause.ast
436
+ end
437
+
438
+ if current_scope = self.global_current_scope
439
+ constraints << current_scope.where_clause.ast
440
+ end
441
+
442
+ um = Arel::UpdateManager.new(arel_table)
443
+ um.set(values.transform_keys { |name| arel_table[name] })
444
+ um.wheres = constraints
384
445
 
385
446
  connection.update(um, "#{self} Update")
386
447
  end
387
448
 
388
449
  def _delete_record(constraints) # :nodoc:
389
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
450
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
451
+
452
+ if default_scopes?(all_queries: true)
453
+ constraints << default_scoped(all_queries: true).where_clause.ast
454
+ end
455
+
456
+ if current_scope = self.global_current_scope
457
+ constraints << current_scope.where_clause.ast
458
+ end
390
459
 
391
- dm = Arel::DeleteManager.new
392
- dm.from(arel_table)
460
+ dm = Arel::DeleteManager.new(arel_table)
393
461
  dm.wheres = constraints
394
462
 
395
463
  connection.delete(dm, "#{self} Destroy")
@@ -411,14 +479,6 @@ module ActiveRecord
411
479
  def discriminate_class_for_record(record)
412
480
  self
413
481
  end
414
-
415
- def _substitute_values(values)
416
- values.map do |name, value|
417
- attr = arel_table[name]
418
- bind = predicate_builder.build_bind_attribute(attr.name, value)
419
- [attr, bind]
420
- end
421
- end
422
482
  end
423
483
 
424
484
  # Returns true if this object hasn't been saved yet -- that is, a record
@@ -434,6 +494,11 @@ module ActiveRecord
434
494
  @previously_new_record
435
495
  end
436
496
 
497
+ # Returns true if this object was previously persisted but now it has been deleted.
498
+ def previously_persisted?
499
+ !new_record? && destroyed?
500
+ end
501
+
437
502
  # Returns true if this object has been destroyed, otherwise returns false.
438
503
  def destroyed?
439
504
  @destroyed
@@ -556,17 +621,17 @@ module ActiveRecord
556
621
  end
557
622
 
558
623
  # Returns an instance of the specified +klass+ with the attributes of the
559
- # current record. This is mostly useful in relation to single-table
560
- # inheritance structures where you want a subclass to appear as the
624
+ # current record. This is mostly useful in relation to single table
625
+ # inheritance (STI) structures where you want a subclass to appear as the
561
626
  # superclass. This can be used along with record identification in
562
627
  # Action Pack to allow, say, <tt>Client < Company</tt> to do something
563
628
  # like render <tt>partial: @client.becomes(Company)</tt> to render that
564
629
  # instance using the companies/company partial instead of clients/client.
565
630
  #
566
631
  # Note: The new instance will share a link to the same attributes as the original class.
567
- # Therefore the sti column value will still be the same.
632
+ # Therefore the STI column value will still be the same.
568
633
  # Any change to the attributes on either instance will affect both instances.
569
- # If you want to change the sti column as well, use #becomes! instead.
634
+ # If you want to change the STI column as well, use #becomes! instead.
570
635
  def becomes(klass)
571
636
  became = klass.allocate
572
637
 
@@ -581,11 +646,11 @@ module ActiveRecord
581
646
  became
582
647
  end
583
648
 
584
- # Wrapper around #becomes that also changes the instance's sti column value.
649
+ # Wrapper around #becomes that also changes the instance's STI column value.
585
650
  # This is especially useful if you want to persist the changed class in your
586
651
  # database.
587
652
  #
588
- # Note: The old instance's sti column value will be changed too, as both objects
653
+ # Note: The old instance's STI column value will be changed too, as both objects
589
654
  # share the same set of attributes.
590
655
  def becomes!(klass)
591
656
  became = becomes(klass)
@@ -671,14 +736,15 @@ module ActiveRecord
671
736
  verify_readonly_attribute(name) || name
672
737
  end
673
738
 
674
- id_in_database = self.id_in_database
675
- attributes.each do |k, v|
676
- write_attribute_without_type_cast(k, v)
739
+ update_constraints = _primary_key_constraints_hash
740
+ attributes = attributes.each_with_object({}) do |(k, v), h|
741
+ h[k] = @attributes.write_cast_value(k, v)
742
+ clear_attribute_change(k)
677
743
  end
678
744
 
679
745
  affected_rows = self.class._update_record(
680
746
  attributes,
681
- @primary_key => id_in_database
747
+ update_constraints
682
748
  )
683
749
 
684
750
  affected_rows == 1
@@ -800,13 +866,13 @@ module ActiveRecord
800
866
  def reload(options = nil)
801
867
  self.class.connection.clear_query_cache
802
868
 
803
- fresh_object =
804
- if options && options[:lock]
805
- self.class.unscoped { self.class.lock(options[:lock]).find(id) }
806
- else
807
- self.class.unscoped { self.class.find(id) }
808
- end
869
+ fresh_object = if apply_scoping?(options)
870
+ _find_record(options)
871
+ else
872
+ self.class.unscoped { _find_record(options) }
873
+ end
809
874
 
875
+ @association_cache = fresh_object.instance_variable_get(:@association_cache)
810
876
  @attributes = fresh_object.instance_variable_get(:@attributes)
811
877
  @new_record = false
812
878
  @previously_new_record = false
@@ -865,6 +931,29 @@ module ActiveRecord
865
931
  end
866
932
 
867
933
  private
934
+ def strict_loaded_associations
935
+ @association_cache.find_all do |_, assoc|
936
+ assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
937
+ end.map(&:first)
938
+ end
939
+
940
+ def _find_record(options)
941
+ if options && options[:lock]
942
+ self.class.preload(strict_loaded_associations).lock(options[:lock]).find(id)
943
+ else
944
+ self.class.preload(strict_loaded_associations).find(id)
945
+ end
946
+ end
947
+
948
+ def apply_scoping?(options)
949
+ !(options && options[:unscoped]) &&
950
+ (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
951
+ end
952
+
953
+ def _primary_key_constraints_hash
954
+ { @primary_key => id_in_database }
955
+ end
956
+
868
957
  # A hook to be overridden by association modules.
869
958
  def destroy_associations
870
959
  end
@@ -874,7 +963,7 @@ module ActiveRecord
874
963
  end
875
964
 
876
965
  def _delete_row
877
- self.class._delete_record(@primary_key => id_in_database)
966
+ self.class._delete_record(_primary_key_constraints_hash)
878
967
  end
879
968
 
880
969
  def _touch_row(attribute_names, time)
@@ -890,7 +979,7 @@ module ActiveRecord
890
979
  def _update_row(attribute_names, attempted_action = "update")
891
980
  self.class._update_record(
892
981
  attributes_with_values(attribute_names),
893
- @primary_key => id_in_database
982
+ _primary_key_constraints_hash
894
983
  )
895
984
  end
896
985