activerecord 7.2.0 → 8.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +189 -745
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/associations/association.rb +25 -5
  5. data/lib/active_record/associations/builder/association.rb +7 -6
  6. data/lib/active_record/associations/collection_association.rb +10 -8
  7. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  8. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  9. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  10. data/lib/active_record/associations/join_dependency.rb +5 -5
  11. data/lib/active_record/associations/preloader/association.rb +2 -2
  12. data/lib/active_record/associations/singular_association.rb +8 -3
  13. data/lib/active_record/associations.rb +34 -4
  14. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  15. data/lib/active_record/attribute_assignment.rb +9 -1
  16. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
  17. data/lib/active_record/attributes.rb +6 -5
  18. data/lib/active_record/autosave_association.rb +69 -27
  19. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  20. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  21. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  22. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +23 -44
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  24. data/lib/active_record/connection_adapters/abstract/query_cache.rb +53 -18
  25. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  26. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  27. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +26 -5
  28. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  29. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -25
  30. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +20 -38
  31. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  32. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  33. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +44 -46
  34. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  35. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  36. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  37. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  38. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  39. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
  40. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -6
  41. data/lib/active_record/connection_adapters/postgresql_adapter.rb +38 -90
  42. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  43. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  44. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  45. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  46. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  47. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -12
  48. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  49. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  50. data/lib/active_record/connection_handling.rb +22 -0
  51. data/lib/active_record/core.rb +16 -9
  52. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
  53. data/lib/active_record/encryption/config.rb +3 -1
  54. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  55. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  56. data/lib/active_record/encryption/encryptor.rb +16 -9
  57. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  58. data/lib/active_record/encryption/key_provider.rb +1 -1
  59. data/lib/active_record/encryption/scheme.rb +8 -1
  60. data/lib/active_record/encryption.rb +2 -0
  61. data/lib/active_record/enum.rb +8 -0
  62. data/lib/active_record/errors.rb +13 -5
  63. data/lib/active_record/fixtures.rb +0 -1
  64. data/lib/active_record/future_result.rb +14 -10
  65. data/lib/active_record/gem_version.rb +3 -3
  66. data/lib/active_record/insert_all.rb +1 -1
  67. data/lib/active_record/migration/command_recorder.rb +22 -5
  68. data/lib/active_record/migration/compatibility.rb +5 -2
  69. data/lib/active_record/migration.rb +35 -33
  70. data/lib/active_record/model_schema.rb +6 -3
  71. data/lib/active_record/nested_attributes.rb +11 -2
  72. data/lib/active_record/persistence.rb +128 -130
  73. data/lib/active_record/query_logs.rb +97 -39
  74. data/lib/active_record/query_logs_formatter.rb +17 -28
  75. data/lib/active_record/querying.rb +6 -6
  76. data/lib/active_record/railtie.rb +8 -14
  77. data/lib/active_record/reflection.rb +19 -10
  78. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  79. data/lib/active_record/relation/batches.rb +135 -75
  80. data/lib/active_record/relation/calculations.rb +24 -19
  81. data/lib/active_record/relation/delegation.rb +25 -14
  82. data/lib/active_record/relation/finder_methods.rb +18 -18
  83. data/lib/active_record/relation/merger.rb +8 -8
  84. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  85. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  86. data/lib/active_record/relation/predicate_builder.rb +6 -1
  87. data/lib/active_record/relation/query_methods.rb +58 -37
  88. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  89. data/lib/active_record/relation/spawn_methods.rb +1 -1
  90. data/lib/active_record/relation.rb +72 -61
  91. data/lib/active_record/result.rb +68 -7
  92. data/lib/active_record/sanitization.rb +7 -6
  93. data/lib/active_record/schema_dumper.rb +5 -0
  94. data/lib/active_record/schema_migration.rb +2 -1
  95. data/lib/active_record/scoping/named.rb +6 -2
  96. data/lib/active_record/statement_cache.rb +12 -12
  97. data/lib/active_record/store.rb +7 -3
  98. data/lib/active_record/tasks/database_tasks.rb +36 -16
  99. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  100. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  101. data/lib/active_record/test_fixtures.rb +12 -0
  102. data/lib/active_record/token_for.rb +1 -1
  103. data/lib/active_record/validations/uniqueness.rb +9 -8
  104. data/lib/active_record.rb +15 -0
  105. data/lib/arel/collectors/bind.rb +1 -1
  106. metadata +14 -14
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "benchmark"
4
3
  require "set"
5
- require "zlib"
6
4
  require "active_support/core_ext/array/access"
7
5
  require "active_support/core_ext/enumerable"
8
6
  require "active_support/core_ext/module/attribute_accessors"
@@ -21,7 +19,7 @@ module ActiveRecord
21
19
  # For example the following migration is not reversible.
22
20
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
23
21
  #
24
- # class IrreversibleMigrationExample < ActiveRecord::Migration[7.2]
22
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[8.0]
25
23
  # def change
26
24
  # create_table :distributors do |t|
27
25
  # t.string :zipcode
@@ -39,7 +37,7 @@ module ActiveRecord
39
37
  #
40
38
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
41
39
  #
42
- # class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
40
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
43
41
  # def up
44
42
  # create_table :distributors do |t|
45
43
  # t.string :zipcode
@@ -64,7 +62,7 @@ module ActiveRecord
64
62
  #
65
63
  # 2. Use the #reversible method in <tt>#change</tt> method:
66
64
  #
67
- # class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
65
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
68
66
  # def change
69
67
  # create_table :distributors do |t|
70
68
  # t.string :zipcode
@@ -250,7 +248,7 @@ module ActiveRecord
250
248
  #
251
249
  # Example of a simple migration:
252
250
  #
253
- # class AddSsl < ActiveRecord::Migration[7.2]
251
+ # class AddSsl < ActiveRecord::Migration[8.0]
254
252
  # def up
255
253
  # add_column :accounts, :ssl_enabled, :boolean, default: true
256
254
  # end
@@ -270,7 +268,7 @@ module ActiveRecord
270
268
  #
271
269
  # Example of a more complex migration that also needs to initialize data:
272
270
  #
273
- # class AddSystemSettings < ActiveRecord::Migration[7.2]
271
+ # class AddSystemSettings < ActiveRecord::Migration[8.0]
274
272
  # def up
275
273
  # create_table :system_settings do |t|
276
274
  # t.string :name
@@ -357,7 +355,7 @@ module ActiveRecord
357
355
  #
358
356
  # === Deletion
359
357
  #
360
- # * <tt>drop_table(name)</tt>: Drops the table called +name+.
358
+ # * <tt>drop_table(*names)</tt>: Drops the given tables.
361
359
  # * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
362
360
  # specified by the given arguments.
363
361
  # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
@@ -399,7 +397,7 @@ module ActiveRecord
399
397
  # $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
400
398
  #
401
399
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
402
- # class AddFieldnameToTablename < ActiveRecord::Migration[7.2]
400
+ # class AddFieldnameToTablename < ActiveRecord::Migration[8.0]
403
401
  # def change
404
402
  # add_column :tablenames, :fieldname, :string
405
403
  # end
@@ -425,7 +423,7 @@ module ActiveRecord
425
423
  #
426
424
  # Not all migrations change the schema. Some just fix the data:
427
425
  #
428
- # class RemoveEmptyTags < ActiveRecord::Migration[7.2]
426
+ # class RemoveEmptyTags < ActiveRecord::Migration[8.0]
429
427
  # def up
430
428
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
431
429
  # end
@@ -438,7 +436,7 @@ module ActiveRecord
438
436
  #
439
437
  # Others remove columns when they migrate up instead of down:
440
438
  #
441
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.2]
439
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.0]
442
440
  # def up
443
441
  # remove_column :items, :incomplete_items_count
444
442
  # remove_column :items, :completed_items_count
@@ -452,7 +450,7 @@ module ActiveRecord
452
450
  #
453
451
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
454
452
  #
455
- # class MakeJoinUnique < ActiveRecord::Migration[7.2]
453
+ # class MakeJoinUnique < ActiveRecord::Migration[8.0]
456
454
  # def up
457
455
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
458
456
  # end
@@ -469,7 +467,7 @@ module ActiveRecord
469
467
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
470
468
  # latest column data from after the new column was added. Example:
471
469
  #
472
- # class AddPeopleSalary < ActiveRecord::Migration[7.2]
470
+ # class AddPeopleSalary < ActiveRecord::Migration[8.0]
473
471
  # def up
474
472
  # add_column :people, :salary, :integer
475
473
  # Person.reset_column_information
@@ -531,7 +529,7 @@ module ActiveRecord
531
529
  # To define a reversible migration, define the +change+ method in your
532
530
  # migration like this:
533
531
  #
534
- # class TenderloveMigration < ActiveRecord::Migration[7.2]
532
+ # class TenderloveMigration < ActiveRecord::Migration[8.0]
535
533
  # def change
536
534
  # create_table(:horses) do |t|
537
535
  # t.column :content, :text
@@ -561,7 +559,7 @@ module ActiveRecord
561
559
  # can't execute inside a transaction though, and for these situations
562
560
  # you can turn the automatic transactions off.
563
561
  #
564
- # class ChangeEnum < ActiveRecord::Migration[7.2]
562
+ # class ChangeEnum < ActiveRecord::Migration[8.0]
565
563
  # disable_ddl_transaction!
566
564
  #
567
565
  # def up
@@ -604,7 +602,7 @@ module ActiveRecord
604
602
  end
605
603
  end
606
604
 
607
- def drop_table(table_name, **options)
605
+ def drop_table(*table_names, **options)
608
606
  if block_given?
609
607
  super { |t| yield compatible_table_definition(t) }
610
608
  else
@@ -715,13 +713,7 @@ module ActiveRecord
715
713
 
716
714
  def load_schema_if_pending!
717
715
  if any_schema_needs_update?
718
- # Roundtrip to Rake to allow plugins to hook into database initialization.
719
- root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
720
-
721
- FileUtils.cd(root) do
722
- Base.connection_handler.clear_all_connections!(:all)
723
- system("bin/rails db:test:prepare")
724
- end
716
+ load_schema!
725
717
  end
726
718
 
727
719
  check_pending_migrations
@@ -785,6 +777,16 @@ module ActiveRecord
785
777
  def env
786
778
  ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
787
779
  end
780
+
781
+ def load_schema!
782
+ # Roundtrip to Rake to allow plugins to hook into database initialization.
783
+ root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
784
+
785
+ FileUtils.cd(root) do
786
+ Base.connection_handler.clear_all_connections!(:all)
787
+ system("bin/rails db:test:prepare")
788
+ end
789
+ end
788
790
  end
789
791
 
790
792
  def disable_ddl_transaction # :nodoc:
@@ -822,7 +824,7 @@ module ActiveRecord
822
824
  # and create the table 'apples' on the way up, and the reverse
823
825
  # on the way down.
824
826
  #
825
- # class FixTLMigration < ActiveRecord::Migration[7.2]
827
+ # class FixTLMigration < ActiveRecord::Migration[8.0]
826
828
  # def change
827
829
  # revert do
828
830
  # create_table(:horses) do |t|
@@ -841,7 +843,7 @@ module ActiveRecord
841
843
  #
842
844
  # require_relative "20121212123456_tenderlove_migration"
843
845
  #
844
- # class FixupTLMigration < ActiveRecord::Migration[7.2]
846
+ # class FixupTLMigration < ActiveRecord::Migration[8.0]
845
847
  # def change
846
848
  # revert TenderloveMigration
847
849
  #
@@ -892,7 +894,7 @@ module ActiveRecord
892
894
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
893
895
  # even when migrating down:
894
896
  #
895
- # class SplitNameMigration < ActiveRecord::Migration[7.2]
897
+ # class SplitNameMigration < ActiveRecord::Migration[8.0]
896
898
  # def change
897
899
  # add_column :users, :first_name, :string
898
900
  # add_column :users, :last_name, :string
@@ -920,7 +922,7 @@ module ActiveRecord
920
922
  # In the following example, the new column +published+ will be given
921
923
  # the value +true+ for all existing records.
922
924
  #
923
- # class AddPublishedToPosts < ActiveRecord::Migration[7.2]
925
+ # class AddPublishedToPosts < ActiveRecord::Migration[8.0]
924
926
  # def change
925
927
  # add_column :posts, :published, :boolean, default: false
926
928
  # up_only do
@@ -972,16 +974,16 @@ module ActiveRecord
972
974
  when :down then announce "reverting"
973
975
  end
974
976
 
975
- time = nil
977
+ time_elapsed = nil
976
978
  ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
977
- time = Benchmark.measure do
979
+ time_elapsed = ActiveSupport::Benchmark.realtime do
978
980
  exec_migration(conn, direction)
979
981
  end
980
982
  end
981
983
 
982
984
  case direction
983
- when :up then announce "migrated (%.4fs)" % time.real; write
984
- when :down then announce "reverted (%.4fs)" % time.real; write
985
+ when :up then announce "migrated (%.4fs)" % time_elapsed; write
986
+ when :down then announce "reverted (%.4fs)" % time_elapsed; write
985
987
  end
986
988
  end
987
989
 
@@ -1022,8 +1024,8 @@ module ActiveRecord
1022
1024
  def say_with_time(message)
1023
1025
  say(message)
1024
1026
  result = nil
1025
- time = Benchmark.measure { result = yield }
1026
- say "%.4fs" % time.real, :subitem
1027
+ time_elapsed = ActiveSupport::Benchmark.realtime { result = yield }
1028
+ say "%.4fs" % time_elapsed, :subitem
1027
1029
  say("#{result} rows", :subitem) if result.is_a?(Integer)
1028
1030
  result
1029
1031
  end
@@ -431,7 +431,6 @@ module ActiveRecord
431
431
  end
432
432
 
433
433
  def columns
434
- load_schema unless @columns
435
434
  @columns ||= columns_hash.values.freeze
436
435
  end
437
436
 
@@ -503,7 +502,7 @@ module ActiveRecord
503
502
  # when just after creating a table you want to populate it with some default
504
503
  # values, e.g.:
505
504
  #
506
- # class CreateJobLevels < ActiveRecord::Migration[7.2]
505
+ # class CreateJobLevels < ActiveRecord::Migration[8.0]
507
506
  # def up
508
507
  # create_table :job_levels do |t|
509
508
  # t.integer :id
@@ -531,7 +530,9 @@ module ActiveRecord
531
530
  initialize_find_by_cache
532
531
  end
533
532
 
534
- def load_schema # :nodoc:
533
+ # Load the model's schema information either from the schema cache
534
+ # or directly from the database.
535
+ def load_schema
535
536
  return if schema_loaded?
536
537
  @load_schema_monitor.synchronize do
537
538
  return if schema_loaded?
@@ -592,6 +593,8 @@ module ActiveRecord
592
593
  columns_hash = schema_cache.columns_hash(table_name)
593
594
  columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
594
595
  @columns_hash = columns_hash.freeze
596
+
597
+ _default_attributes # Precompute to cache DB-dependent attribute types
595
598
  end
596
599
 
597
600
  # Guesses the table name, but does not decorate it with prefix and suffix information.
@@ -524,12 +524,12 @@ module ActiveRecord
524
524
  unless reject_new_record?(association_name, attributes)
525
525
  association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
526
526
  end
527
- elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
527
+ elsif existing_record = find_record_by_id(association.klass, existing_records, attributes["id"])
528
528
  unless call_reject_if(association_name, attributes)
529
529
  # Make sure we are operating on the actual object which is in the association's
530
530
  # proxy_target array (either by finding it, or adding it if not found)
531
531
  # Take into account that the proxy_target may have changed due to callbacks
532
- target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
532
+ target_record = find_record_by_id(association.klass, association.target, attributes["id"])
533
533
  if target_record
534
534
  existing_record = target_record
535
535
  else
@@ -620,5 +620,14 @@ module ActiveRecord
620
620
  raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
621
621
  model, "id", record_id)
622
622
  end
623
+
624
+ def find_record_by_id(klass, records, id)
625
+ if klass.composite_primary_key?
626
+ id = Array(id).map(&:to_s)
627
+ records.find { |record| Array(record.id).map(&:to_s) == id }
628
+ else
629
+ records.find { |record| record.id.to_s == id.to_s }
630
+ end
631
+ end
623
632
  end
624
633
  end
@@ -248,18 +248,16 @@ module ActiveRecord
248
248
 
249
249
  im = Arel::InsertManager.new(arel_table)
250
250
 
251
- with_connection do |c|
252
- if values.empty?
253
- im.insert(connection.empty_insert_statement_value(primary_key))
254
- else
255
- im.insert(values.transform_keys { |name| arel_table[name] })
256
- end
257
-
258
- connection.insert(
259
- im, "#{self} Create", primary_key || false, primary_key_value,
260
- returning: returning
261
- )
251
+ if values.empty?
252
+ im.insert(connection.empty_insert_statement_value(primary_key))
253
+ else
254
+ im.insert(values.transform_keys { |name| arel_table[name] })
262
255
  end
256
+
257
+ connection.insert(
258
+ im, "#{self} Create", primary_key || false, primary_key_value,
259
+ returning: returning
260
+ )
263
261
  end
264
262
 
265
263
  def _update_record(values, constraints) # :nodoc:
@@ -812,159 +810,159 @@ module ActiveRecord
812
810
  end
813
811
  end
814
812
 
815
- private
816
- def init_internals
817
- super
818
- @_trigger_destroy_callback = @_trigger_update_callback = nil
819
- @previously_new_record = false
820
- end
813
+ private
814
+ def init_internals
815
+ super
816
+ @_trigger_destroy_callback = @_trigger_update_callback = nil
817
+ @previously_new_record = false
818
+ end
821
819
 
822
- def strict_loaded_associations
823
- @association_cache.find_all do |_, assoc|
824
- assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
825
- end.map(&:first)
826
- end
820
+ def strict_loaded_associations
821
+ @association_cache.find_all do |_, assoc|
822
+ assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
823
+ end.map(&:first)
824
+ end
827
825
 
828
- def _find_record(options)
829
- all_queries = options ? options[:all_queries] : nil
830
- base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
826
+ def _find_record(options)
827
+ all_queries = options ? options[:all_queries] : nil
828
+ base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
831
829
 
832
- if options && options[:lock]
833
- base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
834
- else
835
- base.find_by!(_in_memory_query_constraints_hash)
830
+ if options && options[:lock]
831
+ base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
832
+ else
833
+ base.find_by!(_in_memory_query_constraints_hash)
834
+ end
836
835
  end
837
- end
838
836
 
839
- def _in_memory_query_constraints_hash
840
- if self.class.query_constraints_list.nil?
841
- { @primary_key => id }
842
- else
843
- self.class.query_constraints_list.index_with do |column_name|
844
- attribute(column_name)
837
+ def _in_memory_query_constraints_hash
838
+ if self.class.query_constraints_list.nil?
839
+ { @primary_key => id }
840
+ else
841
+ self.class.query_constraints_list.index_with do |column_name|
842
+ attribute(column_name)
843
+ end
845
844
  end
846
845
  end
847
- end
848
846
 
849
- def apply_scoping?(options)
850
- !(options && options[:unscoped]) &&
851
- (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
852
- end
847
+ def apply_scoping?(options)
848
+ !(options && options[:unscoped]) &&
849
+ (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
850
+ end
853
851
 
854
- def _query_constraints_hash
855
- if self.class.query_constraints_list.nil?
856
- { @primary_key => id_in_database }
857
- else
858
- self.class.query_constraints_list.index_with do |column_name|
859
- attribute_in_database(column_name)
852
+ def _query_constraints_hash
853
+ if self.class.query_constraints_list.nil?
854
+ { @primary_key => id_in_database }
855
+ else
856
+ self.class.query_constraints_list.index_with do |column_name|
857
+ attribute_in_database(column_name)
858
+ end
860
859
  end
861
860
  end
862
- end
863
861
 
864
- # A hook to be overridden by association modules.
865
- def destroy_associations
866
- end
867
-
868
- def destroy_row
869
- _delete_row
870
- end
871
-
872
- def _delete_row
873
- self.class._delete_record(_query_constraints_hash)
874
- end
862
+ # A hook to be overridden by association modules.
863
+ def destroy_associations
864
+ end
875
865
 
876
- def _touch_row(attribute_names, time)
877
- time ||= current_time_from_proper_timezone
866
+ def destroy_row
867
+ _delete_row
868
+ end
878
869
 
879
- attribute_names.each do |attr_name|
880
- _write_attribute(attr_name, time)
870
+ def _delete_row
871
+ self.class._delete_record(_query_constraints_hash)
881
872
  end
882
873
 
883
- _update_row(attribute_names, "touch")
884
- end
874
+ def _touch_row(attribute_names, time)
875
+ time ||= current_time_from_proper_timezone
885
876
 
886
- def _update_row(attribute_names, attempted_action = "update")
887
- self.class._update_record(
888
- attributes_with_values(attribute_names),
889
- _query_constraints_hash
890
- )
891
- end
877
+ attribute_names.each do |attr_name|
878
+ _write_attribute(attr_name, time)
879
+ end
892
880
 
893
- def create_or_update(**, &block)
894
- _raise_readonly_record_error if readonly?
895
- return false if destroyed?
896
- result = new_record? ? _create_record(&block) : _update_record(&block)
897
- result != false
898
- end
881
+ _update_row(attribute_names, "touch")
882
+ end
899
883
 
900
- # Updates the associated record with values matching those of the instance attributes.
901
- # Returns the number of affected rows.
902
- def _update_record(attribute_names = self.attribute_names)
903
- attribute_names = attributes_for_update(attribute_names)
884
+ def _update_row(attribute_names, attempted_action = "update")
885
+ self.class._update_record(
886
+ attributes_with_values(attribute_names),
887
+ _query_constraints_hash
888
+ )
889
+ end
904
890
 
905
- if attribute_names.empty?
906
- affected_rows = 0
907
- @_trigger_update_callback = true
908
- else
909
- affected_rows = _update_row(attribute_names)
910
- @_trigger_update_callback = affected_rows == 1
891
+ def create_or_update(**, &block)
892
+ _raise_readonly_record_error if readonly?
893
+ return false if destroyed?
894
+ result = new_record? ? _create_record(&block) : _update_record(&block)
895
+ result != false
911
896
  end
912
897
 
913
- @previously_new_record = false
898
+ # Updates the associated record with values matching those of the instance attributes.
899
+ # Returns the number of affected rows.
900
+ def _update_record(attribute_names = self.attribute_names)
901
+ attribute_names = attributes_for_update(attribute_names)
914
902
 
915
- yield(self) if block_given?
903
+ if attribute_names.empty?
904
+ affected_rows = 0
905
+ @_trigger_update_callback = true
906
+ else
907
+ affected_rows = _update_row(attribute_names)
908
+ @_trigger_update_callback = affected_rows == 1
909
+ end
916
910
 
917
- affected_rows
918
- end
911
+ @previously_new_record = false
919
912
 
920
- # Creates a record with values matching those of the instance attributes
921
- # and returns its id.
922
- def _create_record(attribute_names = self.attribute_names)
923
- attribute_names = attributes_for_create(attribute_names)
913
+ yield(self) if block_given?
924
914
 
925
- self.class.with_connection do |connection|
926
- returning_columns = self.class._returning_columns_for_insert(connection)
915
+ affected_rows
916
+ end
927
917
 
928
- returning_values = self.class._insert_record(
929
- connection,
930
- attributes_with_values(attribute_names),
931
- returning_columns
932
- )
918
+ # Creates a record with values matching those of the instance attributes
919
+ # and returns its id.
920
+ def _create_record(attribute_names = self.attribute_names)
921
+ attribute_names = attributes_for_create(attribute_names)
933
922
 
934
- returning_columns.zip(returning_values).each do |column, value|
935
- _write_attribute(column, value) if !_read_attribute(column)
936
- end if returning_values
937
- end
923
+ self.class.with_connection do |connection|
924
+ returning_columns = self.class._returning_columns_for_insert(connection)
938
925
 
939
- @new_record = false
940
- @previously_new_record = true
926
+ returning_values = self.class._insert_record(
927
+ connection,
928
+ attributes_with_values(attribute_names),
929
+ returning_columns
930
+ )
941
931
 
942
- yield(self) if block_given?
932
+ returning_columns.zip(returning_values).each do |column, value|
933
+ _write_attribute(column, value) if !_read_attribute(column)
934
+ end if returning_values
935
+ end
943
936
 
944
- id
945
- end
937
+ @new_record = false
938
+ @previously_new_record = true
946
939
 
947
- def verify_readonly_attribute(name)
948
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
949
- end
940
+ yield(self) if block_given?
950
941
 
951
- def _raise_record_not_destroyed
952
- @_association_destroy_exception ||= nil
953
- key = self.class.primary_key
954
- raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
955
- ensure
956
- @_association_destroy_exception = nil
957
- end
942
+ id
943
+ end
958
944
 
959
- def _raise_readonly_record_error
960
- raise ReadOnlyRecord, "#{self.class} is marked as readonly"
961
- end
945
+ def verify_readonly_attribute(name)
946
+ raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
947
+ end
962
948
 
963
- def _raise_record_not_touched_error
964
- raise ActiveRecordError, <<~MSG.squish
965
- Cannot touch on a new or destroyed record object. Consider using
966
- persisted?, new_record?, or destroyed? before touching.
967
- MSG
968
- end
949
+ def _raise_record_not_destroyed
950
+ @_association_destroy_exception ||= nil
951
+ key = self.class.primary_key
952
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
953
+ ensure
954
+ @_association_destroy_exception = nil
955
+ end
956
+
957
+ def _raise_readonly_record_error
958
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
959
+ end
960
+
961
+ def _raise_record_not_touched_error
962
+ raise ActiveRecordError, <<~MSG.squish
963
+ Cannot touch on a new or destroyed record object. Consider using
964
+ persisted?, new_record?, or destroyed? before touching.
965
+ MSG
966
+ end
969
967
  end
970
968
  end