activerecord 7.0.0 → 7.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +357 -0
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_record/associations/collection_association.rb +1 -2
  5. data/lib/active_record/associations/collection_proxy.rb +2 -2
  6. data/lib/active_record/associations/has_many_association.rb +7 -4
  7. data/lib/active_record/associations/join_dependency.rb +17 -13
  8. data/lib/active_record/associations.rb +38 -17
  9. data/lib/active_record/attribute_methods/serialization.rb +34 -50
  10. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
  11. data/lib/active_record/attribute_methods.rb +2 -2
  12. data/lib/active_record/autosave_association.rb +2 -2
  13. data/lib/active_record/base.rb +3 -3
  14. data/lib/active_record/coders/yaml_column.rb +10 -2
  15. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -1
  16. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  17. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -4
  18. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  19. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -7
  20. data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
  21. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +10 -2
  22. data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
  23. data/lib/active_record/connection_adapters/mysql/quoting.rb +3 -1
  24. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  25. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  26. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
  27. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -0
  28. data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
  29. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
  30. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +10 -3
  31. data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -5
  32. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
  33. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -14
  34. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +35 -2
  35. data/lib/active_record/connection_handling.rb +2 -2
  36. data/lib/active_record/core.rb +3 -3
  37. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -0
  38. data/lib/active_record/database_configurations.rb +1 -1
  39. data/lib/active_record/delegated_type.rb +1 -1
  40. data/lib/active_record/encryption/configurable.rb +9 -3
  41. data/lib/active_record/encryption/contexts.rb +3 -3
  42. data/lib/active_record/encryption/derived_secret_key_provider.rb +1 -1
  43. data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
  44. data/lib/active_record/encryption/encryptable_record.rb +2 -4
  45. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  46. data/lib/active_record/encryption/encryptor.rb +7 -7
  47. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
  48. data/lib/active_record/encryption/extended_deterministic_queries.rb +28 -28
  49. data/lib/active_record/encryption/message.rb +1 -1
  50. data/lib/active_record/encryption/properties.rb +1 -1
  51. data/lib/active_record/encryption/scheme.rb +1 -1
  52. data/lib/active_record/enum.rb +1 -1
  53. data/lib/active_record/fixtures.rb +5 -5
  54. data/lib/active_record/gem_version.rb +2 -2
  55. data/lib/active_record/integration.rb +2 -2
  56. data/lib/active_record/locking/pessimistic.rb +3 -3
  57. data/lib/active_record/log_subscriber.rb +10 -5
  58. data/lib/active_record/middleware/database_selector.rb +13 -6
  59. data/lib/active_record/middleware/shard_selector.rb +4 -4
  60. data/lib/active_record/migration/command_recorder.rb +3 -3
  61. data/lib/active_record/migration/compatibility.rb +10 -7
  62. data/lib/active_record/migration.rb +6 -5
  63. data/lib/active_record/model_schema.rb +22 -10
  64. data/lib/active_record/persistence.rb +9 -8
  65. data/lib/active_record/querying.rb +1 -1
  66. data/lib/active_record/railtie.rb +22 -18
  67. data/lib/active_record/railties/databases.rake +16 -11
  68. data/lib/active_record/reflection.rb +7 -1
  69. data/lib/active_record/relation/batches.rb +3 -3
  70. data/lib/active_record/relation/calculations.rb +3 -2
  71. data/lib/active_record/relation/delegation.rb +1 -1
  72. data/lib/active_record/relation/query_methods.rb +46 -11
  73. data/lib/active_record/relation.rb +22 -6
  74. data/lib/active_record/sanitization.rb +6 -5
  75. data/lib/active_record/schema.rb +38 -23
  76. data/lib/active_record/schema_dumper.rb +15 -16
  77. data/lib/active_record/scoping/default.rb +5 -7
  78. data/lib/active_record/serialization.rb +5 -0
  79. data/lib/active_record/signed_id.rb +2 -2
  80. data/lib/active_record/store.rb +7 -2
  81. data/lib/active_record/tasks/database_tasks.rb +32 -23
  82. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -2
  83. data/lib/active_record/test_fixtures.rb +12 -5
  84. data/lib/active_record/translation.rb +1 -1
  85. data/lib/active_record/validations/associated.rb +3 -3
  86. data/lib/active_record/validations/presence.rb +2 -2
  87. data/lib/active_record/validations/uniqueness.rb +3 -3
  88. data/lib/active_record/version.rb +1 -1
  89. data/lib/active_record.rb +15 -1
  90. metadata +13 -13
@@ -75,7 +75,7 @@ module ActiveRecord
75
75
 
76
76
  class << self
77
77
  def new_client(conn_params)
78
- PG.connect(conn_params)
78
+ PG.connect(**conn_params)
79
79
  rescue ::PG::Error => error
80
80
  if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
81
81
  raise ActiveRecord::NoDatabaseError.db_error(conn_params[:dbname])
@@ -104,7 +104,7 @@ module ActiveRecord
104
104
 
105
105
  ##
106
106
  # :singleton-method:
107
- # PostgreSQL supports multiple types for DateTimes. By default if you use `datetime`
107
+ # PostgreSQL supports multiple types for DateTimes. By default, if you use +datetime+
108
108
  # in migrations, Rails will translate this to a PostgreSQL "timestamp without time zone".
109
109
  # Change this in an initializer to use another NATIVE_DATABASE_TYPES. For example, to
110
110
  # store DateTimes as "timestamp with time zone":
@@ -116,8 +116,8 @@ module ActiveRecord
116
116
  # ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" }
117
117
  # ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :my_custom_type
118
118
  #
119
- # If you're using :ruby as your config.active_record.schema_format and you change this
120
- # setting, you should immediately run bin/rails db:migrate to update the types in your schema.rb.
119
+ # If you're using +:ruby+ as your +config.active_record.schema_format+ and you change this
120
+ # setting, you should immediately run <tt>bin/rails db:migrate</tt> to update the types in your schema.rb.
121
121
  class_attribute :datetime_type, default: :timestamp
122
122
 
123
123
  NATIVE_DATABASE_TYPES = {
@@ -281,7 +281,7 @@ module ActiveRecord
281
281
  def initialize(connection, logger, connection_parameters, config)
282
282
  super(connection, logger, config)
283
283
 
284
- @connection_parameters = connection_parameters
284
+ @connection_parameters = connection_parameters || {}
285
285
 
286
286
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
287
287
  @local_tz = nil
@@ -1063,5 +1063,6 @@ module ActiveRecord
1063
1063
  ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
1064
1064
  ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
1065
1065
  end
1066
+ ActiveSupport.run_load_hooks(:active_record_postgresqladapter, PostgreSQLAdapter)
1066
1067
  end
1067
1068
  end
@@ -45,6 +45,19 @@ module ActiveRecord
45
45
  0
46
46
  end
47
47
 
48
+ def quote_default_expression(value, column) # :nodoc:
49
+ if value.is_a?(Proc)
50
+ value = value.call
51
+ if value.match?(/\A\w+\(.*\)\z/)
52
+ "(#{value})"
53
+ else
54
+ value
55
+ end
56
+ else
57
+ super
58
+ end
59
+ end
60
+
48
61
  def type_cast(value) # :nodoc:
49
62
  case value
50
63
  when BigDecimal
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  WHERE name = #{quote(row['name'])} AND type = 'index'
22
22
  SQL
23
23
 
24
- /\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?\z/i =~ index_sql
24
+ /\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?(?:\s*\/\*.*\*\/)?\z/i =~ index_sql
25
25
 
26
26
  columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
27
27
  col["name"]
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  def remove_foreign_key(from_table, to_table = nil, **options)
63
- return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
63
+ return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
64
64
 
65
65
  to_table ||= options[:to_table]
66
66
  options = options.except(:name, :to_table, :validate)
@@ -127,20 +127,20 @@ module ActiveRecord
127
127
  end
128
128
 
129
129
  def new_column_from_field(table_name, field)
130
- default = \
131
- case field["dflt_value"]
132
- when /^null$/i
133
- nil
134
- when /^'(.*)'$/m
135
- $1.gsub("''", "'")
136
- when /^"(.*)"$/m
137
- $1.gsub('""', '"')
138
- else
139
- field["dflt_value"]
140
- end
130
+ default = field["dflt_value"]
141
131
 
142
132
  type_metadata = fetch_type_metadata(field["type"])
143
- Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, collation: field["collation"])
133
+ default_value = extract_value_from_default(default)
134
+ default_function = extract_default_function(default_value, default)
135
+
136
+ Column.new(
137
+ field["name"],
138
+ default_value,
139
+ type_metadata,
140
+ field["notnull"].to_i == 0,
141
+ default_function,
142
+ collation: field["collation"]
143
+ )
144
144
  end
145
145
 
146
146
  def data_source_sql(name = nil, type: nil)
@@ -341,7 +341,7 @@ module ActiveRecord
341
341
  end
342
342
 
343
343
  def get_database_version # :nodoc:
344
- SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
344
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
345
345
  end
346
346
 
347
347
  def check_version # :nodoc:
@@ -389,6 +389,34 @@ module ActiveRecord
389
389
  end
390
390
  alias column_definitions table_structure
391
391
 
392
+ def extract_value_from_default(default)
393
+ case default
394
+ when /^null$/i
395
+ nil
396
+ # Quoted types
397
+ when /^'(.*)'$/m
398
+ $1.gsub("''", "'")
399
+ # Quoted types
400
+ when /^"(.*)"$/m
401
+ $1.gsub('""', '"')
402
+ # Numeric types
403
+ when /\A-?\d+(\.\d*)?\z/
404
+ $&
405
+ else
406
+ # Anything else is blank or some function
407
+ # and we can't know the value of that, so return nil.
408
+ nil
409
+ end
410
+ end
411
+
412
+ def extract_default_function(default_value, default)
413
+ default if has_default_function?(default_value, default)
414
+ end
415
+
416
+ def has_default_function?(default_value, default)
417
+ !default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
418
+ end
419
+
392
420
  # See: https://www.sqlite.org/lang_altertable.html
393
421
  # SQLite has an additional restriction on the ALTER TABLE statement
394
422
  def invalid_alter_table_type?(type, options)
@@ -449,8 +477,13 @@ module ActiveRecord
449
477
  options[:rename][column.name.to_sym] ||
450
478
  column.name) : column.name
451
479
 
480
+ if column.has_default?
481
+ type = lookup_cast_type_from_column(column)
482
+ default = type.deserialize(column.default)
483
+ end
484
+
452
485
  @definition.column(column_name, column.type,
453
- limit: column.limit, default: column.default,
486
+ limit: column.limit, default: default,
454
487
  precision: column.precision, scale: column.scale,
455
488
  null: column.null, collation: column.collation,
456
489
  primary_key: column_name == from_primary_key
@@ -44,7 +44,7 @@ module ActiveRecord
44
44
  #
45
45
  # ActiveRecord::Base.establish_connection(:production)
46
46
  #
47
- # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
47
+ # The exceptions AdapterNotSpecified, AdapterNotFound, and +ArgumentError+
48
48
  # may be returned on an error.
49
49
  def establish_connection(config_or_env = nil)
50
50
  config_or_env ||= DEFAULT_ENV.call.to_sym
@@ -108,7 +108,7 @@ module ActiveRecord
108
108
  connections
109
109
  end
110
110
 
111
- # Connects to a role (ex writing, reading or a custom role) and/or
111
+ # Connects to a role (e.g. writing, reading, or a custom role) and/or
112
112
  # shard for the duration of the block. At the end of the block the
113
113
  # connection will be returned to the original role / shard.
114
114
  #
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  ##
61
61
  # :singleton-method:
62
62
  # Force enumeration of all columns in SELECT statements.
63
- # e.g. `SELECT first_name, last_name FROM ...` instead of `SELECT * FROM ...`
63
+ # e.g. <tt>SELECT first_name, last_name FROM ...</tt> instead of <tt>SELECT * FROM ...</tt>
64
64
  # This avoids +PreparedStatementCacheExpired+ errors when a column is added
65
65
  # to the database while the app is running.
66
66
  class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false
@@ -238,7 +238,7 @@ module ActiveRecord
238
238
  def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
239
239
  case ActiveRecord.action_on_strict_loading_violation
240
240
  when :raise
241
- message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
241
+ message = reflection.strict_loading_violation_message(owner)
242
242
  raise ActiveRecord::StrictLoadingViolationError.new(message)
243
243
  when :log
244
244
  name = "strict_loading_violation.active_record"
@@ -411,7 +411,7 @@ module ActiveRecord
411
411
  end
412
412
  end
413
413
 
414
- # Overwrite the default class equality method to provide support for decorated models.
414
+ # Override the default class equality method to provide support for decorated models.
415
415
  def ===(object) # :nodoc:
416
416
  object.is_a?(self)
417
417
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "uri"
4
4
  require "active_support/core_ext/enumerable"
5
+ require "active_support/core_ext/hash/reverse_merge"
5
6
 
6
7
  module ActiveRecord
7
8
  class DatabaseConfigurations
@@ -38,7 +38,7 @@ module ActiveRecord
38
38
  # the returned list. Most of the time we're only iterating over the write
39
39
  # connection (i.e. migrations don't need to run for the write and read connection).
40
40
  # Defaults to +false+.
41
- # * <tt>include_hidden:</tte Determines whether to include replicas and configurations
41
+ # * <tt>include_hidden:</tt> Determines whether to include replicas and configurations
42
42
  # hidden by +database_tasks: false+ in the returned list. Most of the time we're only
43
43
  # iterating over the primary connections (i.e. migrations don't need to run for the
44
44
  # write and read connection). Defaults to +false+.
@@ -136,7 +136,7 @@ module ActiveRecord
136
136
  # end
137
137
  # end
138
138
  #
139
- # Now you can list a bunch of entries, call +Entry#title+, and polymorphism will provide you with the answer.
139
+ # Now you can list a bunch of entries, call <tt>Entry#title</tt>, and polymorphism will provide you with the answer.
140
140
  #
141
141
  # == Nested Attributes
142
142
  #
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Encryption
5
- # Configuration API for +ActiveRecord::Encryption+
5
+ # Configuration API for ActiveRecord::Encryption
6
6
  module Configurable
7
7
  extend ActiveSupport::Concern
8
8
 
@@ -50,11 +50,17 @@ module ActiveRecord
50
50
  end
51
51
  end
52
52
 
53
- def install_auto_filtered_parameters(application) # :nodoc:
53
+ def install_auto_filtered_parameters_hook(application) # :nodoc:
54
54
  ActiveRecord::Encryption.on_encrypted_attribute_declared do |klass, encrypted_attribute_name|
55
- application.config.filter_parameters << encrypted_attribute_name unless ActiveRecord::Encryption.config.excluded_from_filter_parameters.include?(name)
55
+ filter_parameter = [("#{klass.model_name.element}" if klass.name), encrypted_attribute_name.to_s].compact.join(".")
56
+ application.config.filter_parameters << filter_parameter unless excluded_from_filter_parameters?(filter_parameter)
56
57
  end
57
58
  end
59
+
60
+ private
61
+ def excluded_from_filter_parameters?(filter_parameter)
62
+ ActiveRecord::Encryption.config.excluded_from_filter_parameters.find { |excluded_filter| excluded_filter.to_s == filter_parameter }
63
+ end
58
64
  end
59
65
  end
60
66
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Encryption
5
- # +ActiveRecord::Encryption+ uses encryption contexts to configure the different entities used to
5
+ # ActiveRecord::Encryption uses encryption contexts to configure the different entities used to
6
6
  # encrypt/decrypt at a given moment in time.
7
7
  #
8
- # By default, the library uses a default encryption context. This is the +Context+ that gets configured
8
+ # By default, the library uses a default encryption context. This is the Context that gets configured
9
9
  # initially via +config.active_record.encryption+ options. Library users can define nested encryption contexts
10
10
  # when running blocks of code.
11
11
  #
12
- # See +Context+.
12
+ # See Context.
13
13
  module Contexts
14
14
  extend ActiveSupport::Concern
15
15
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Encryption
5
- # A +KeyProvider+ that derives keys from passwords.
5
+ # A KeyProvider that derives keys from passwords.
6
6
  class DerivedSecretKeyProvider < KeyProvider
7
7
  def initialize(passwords)
8
8
  super(Array(passwords).collect { |password| Key.derive_from(password) })
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Encryption
5
- # A +KeyProvider+ that derives keys from passwords.
5
+ # A KeyProvider that derives keys from passwords.
6
6
  class DeterministicKeyProvider < DerivedSecretKeyProvider
7
7
  def initialize(password)
8
8
  passwords = Array(password)
@@ -18,12 +18,10 @@ module ActiveRecord
18
18
  #
19
19
  # === Options
20
20
  #
21
- # * <tt>:key_provider</tt> - Configure a +KeyProvider+ for serving the keys to encrypt and
22
- # decrypt this attribute. If not provided, it will default to +ActiveRecord::Encryption.key_provider+.
21
+ # * <tt>:key_provider</tt> - A key provider to provide encryption and decryption keys. Defaults to
22
+ # +ActiveRecord::Encryption.key_provider+.
23
23
  # * <tt>:key</tt> - A password to derive the key from. It's a shorthand for a +:key_provider+ that
24
24
  # serves derivated keys. Both options can't be used at the same time.
25
- # * <tt>:key_provider</tt> - Set a +:key_provider+ to provide encryption and decryption keys. If not
26
- # provided, it will default to the key provider set with `config.key_provider`.
27
25
  # * <tt>:deterministic</tt> - By default, encryption is not deterministic. It will use a random
28
26
  # initialization vector for each encryption operation. This means that encrypting the same content
29
27
  # with the same key twice will generate different ciphertexts. When set to +true+, it will generate the
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Encryption
5
- # An +ActiveModel::Type+ that encrypts/decrypts strings of text.
5
+ # An ActiveModel::Type::Value that encrypts/decrypts strings of text.
6
6
  #
7
7
  # This is the central piece that connects the encryption system with +encrypts+ declarations in the
8
8
  # model classes. Whenever you declare an attribute as encrypted, it configures an +EncryptedAttributeType+
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  #
20
20
  # * <tt>:scheme</tt> - A +Scheme+ with the encryption properties for this attribute.
21
21
  # * <tt>:cast_type</tt> - A type that will be used to serialize (before encrypting) and deserialize
22
- # (after decrypting). +ActiveModel::Type::String+ by default.
22
+ # (after decrypting). ActiveModel::Type::String by default.
23
23
  def initialize(scheme:, cast_type: ActiveModel::Type::String.new, previous_type: false)
24
24
  super()
25
25
  @scheme = scheme
@@ -6,17 +6,17 @@ require "active_support/core_ext/numeric"
6
6
 
7
7
  module ActiveRecord
8
8
  module Encryption
9
- # An encryptor exposes the encryption API that +ActiveRecord::Encryption::EncryptedAttributeType+
9
+ # An encryptor exposes the encryption API that ActiveRecord::Encryption::EncryptedAttributeType
10
10
  # uses for encrypting and decrypting attribute values.
11
11
  #
12
- # It interacts with a +KeyProvider+ for getting the keys, and delegate to
13
- # +ActiveRecord::Encryption::Cipher+ the actual encryption algorithm.
12
+ # It interacts with a KeyProvider for getting the keys, and delegate to
13
+ # ActiveRecord::Encryption::Cipher the actual encryption algorithm.
14
14
  class Encryptor
15
15
  # Encrypts +clean_text+ and returns the encrypted result
16
16
  #
17
17
  # Internally, it will:
18
18
  #
19
- # 1. Create a new +ActiveRecord::Encryption::Message+
19
+ # 1. Create a new ActiveRecord::Encryption::Message
20
20
  # 2. Compress and encrypt +clean_text+ as the message payload
21
21
  # 3. Serialize it with +ActiveRecord::Encryption.message_serializer+ (+ActiveRecord::Encryption::SafeMarshal+
22
22
  # by default)
@@ -26,10 +26,10 @@ module ActiveRecord
26
26
  #
27
27
  # [:key_provider]
28
28
  # Key provider to use for the encryption operation. It will default to
29
- # +ActiveRecord::Encryption.key_provider+ when not provided
29
+ # +ActiveRecord::Encryption.key_provider+ when not provided.
30
30
  #
31
31
  # [:cipher_options]
32
- # +Cipher+-specific options that will be passed to the Cipher configured in
32
+ # Cipher-specific options that will be passed to the Cipher configured in
33
33
  # +ActiveRecord::Encryption.cipher+
34
34
  def encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
35
35
  clear_text = force_encoding_if_needed(clear_text) if cipher_options[:deterministic]
@@ -47,7 +47,7 @@ module ActiveRecord
47
47
  # +ActiveRecord::Encryption.key_provider+ when not provided
48
48
  #
49
49
  # [:cipher_options]
50
- # +Cipher+-specific options that will be passed to the Cipher configured in
50
+ # Cipher-specific options that will be passed to the Cipher configured in
51
51
  # +ActiveRecord::Encryption.cipher+
52
52
  def decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
53
53
  message = deserialize_message(encrypted_text)
@@ -4,13 +4,13 @@ module ActiveRecord
4
4
  module Encryption
5
5
  # Implements a simple envelope encryption approach where:
6
6
  #
7
- # * It generates a random data-encryption key for each encryption operation
7
+ # * It generates a random data-encryption key for each encryption operation.
8
8
  # * It stores the generated key along with the encrypted payload. It encrypts this key
9
- # with the master key provided in the credential +active_record.encryption.master key+
9
+ # with the master key provided in the +active_record_encryption.primary_key+ credential.
10
10
  #
11
11
  # This provider can work with multiple master keys. It will use the last one for encrypting.
12
12
  #
13
- # When `config.store_key_references` is true, it will also store a reference to
13
+ # When +config.active_record.encryption.store_key_references+ is true, it will also store a reference to
14
14
  # the specific master key that was used to encrypt the data-encryption key. When not set,
15
15
  # it will try all the configured master keys looking for the right one, in order to
16
16
  # return the right decryption key.
@@ -1,35 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Automatically expand encrypted arguments to support querying both encrypted and unencrypted data
4
- #
5
- # Active Record Encryption supports querying the db using deterministic attributes. For example:
6
- #
7
- # Contact.find_by(email_address: "jorge@hey.com")
8
- #
9
- # The value "jorge@hey.com" will get encrypted automatically to perform the query. But there is
10
- # a problem while the data is being encrypted. This won't work. During that time, you need these
11
- # queries to be:
12
- #
13
- # Contact.find_by(email_address: [ "jorge@hey.com", "<encrypted jorge@hey.com>" ])
14
- #
15
- # This patches ActiveRecord to support this automatically. It addresses both:
16
- #
17
- # * ActiveRecord::Base: Used in +Contact.find_by_email_address(...)+
18
- # * ActiveRecord::Relation: Used in +Contact.internal.find_by_email_address(...)+
19
- #
20
- # +ActiveRecord::Base+ relies on +ActiveRecord::Relation+ (+ActiveRecord::QueryMethods+) but it does
21
- # some prepared statements caching. That's why we need to intercept +ActiveRecord::Base+ as soon
22
- # as it's invoked (so that the proper prepared statement is cached).
23
- #
24
- # When modifying this file run performance tests in +test/performance/extended_deterministic_queries_performance_test.rb+ to
25
- # make sure performance overhead is acceptable.
26
- #
27
- # We will extend this to support previous "encryption context" versions in future iterations
28
- #
29
- # @TODO Experimental. Support for every kind of query is pending
30
- # @TODO It should not patch anything if not needed (no previous schemes or no support for previous encryption schemes)
31
3
  module ActiveRecord
32
4
  module Encryption
5
+ # Automatically expand encrypted arguments to support querying both encrypted and unencrypted data
6
+ #
7
+ # Active Record \Encryption supports querying the db using deterministic attributes. For example:
8
+ #
9
+ # Contact.find_by(email_address: "jorge@hey.com")
10
+ #
11
+ # The value "jorge@hey.com" will get encrypted automatically to perform the query. But there is
12
+ # a problem while the data is being encrypted. This won't work. During that time, you need these
13
+ # queries to be:
14
+ #
15
+ # Contact.find_by(email_address: [ "jorge@hey.com", "<encrypted jorge@hey.com>" ])
16
+ #
17
+ # This patches ActiveRecord to support this automatically. It addresses both:
18
+ #
19
+ # * ActiveRecord::Base - Used in <tt>Contact.find_by_email_address(...)</tt>
20
+ # * ActiveRecord::Relation - Used in <tt>Contact.internal.find_by_email_address(...)</tt>
21
+ #
22
+ # ActiveRecord::Base relies on ActiveRecord::Relation (ActiveRecord::QueryMethods) but it does
23
+ # some prepared statements caching. That's why we need to intercept +ActiveRecord::Base+ as soon
24
+ # as it's invoked (so that the proper prepared statement is cached).
25
+ #
26
+ # When modifying this file run performance tests in +test/performance/extended_deterministic_queries_performance_test.rb+ to
27
+ # make sure performance overhead is acceptable.
28
+ #
29
+ # We will extend this to support previous "encryption context" versions in future iterations
30
+ #
31
+ # @TODO Experimental. Support for every kind of query is pending
32
+ # @TODO It should not patch anything if not needed (no previous schemes or no support for previous encryption schemes)
33
33
  module ExtendedDeterministicQueries
34
34
  def self.install_support
35
35
  ActiveRecord::Relation.prepend(RelationQueries)
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  # * An encrypted payload
8
8
  # * A list of unencrypted headers
9
9
  #
10
- # See +Encryptor#encrypt+
10
+ # See Encryptor#encrypt
11
11
  class Message
12
12
  attr_accessor :payload, :headers
13
13
 
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  #
13
13
  # message.headers.encrypted_data_key # instead of message.headers[:k]
14
14
  #
15
- # See +Properties#DEFAULT_PROPERTIES+, +Key+, +Message+
15
+ # See +Properties::DEFAULT_PROPERTIES+, Key, Message
16
16
  class Properties
17
17
  ALLOWED_VALUE_CLASSES = [String, ActiveRecord::Encryption::Message, Numeric, TrueClass, FalseClass, Symbol, NilClass]
18
18
 
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  #
7
7
  # It validates and serves attribute encryption options.
8
8
  #
9
- # See +EncryptedAttributeType+, +Context+
9
+ # See EncryptedAttributeType, Context
10
10
  class Scheme
11
11
  attr_accessor :previous_schemes
12
12
 
@@ -83,7 +83,7 @@ module ActiveRecord
83
83
  #
84
84
  # In rare circumstances you might need to access the mapping directly.
85
85
  # The mappings are exposed through a class method with the pluralized attribute
86
- # name, which return the mapping in a +HashWithIndifferentAccess+:
86
+ # name, which return the mapping in a ActiveSupport::HashWithIndifferentAccess :
87
87
  #
88
88
  # Conversation.statuses[:active] # => 0
89
89
  # Conversation.statuses["archived"] # => 1
@@ -241,13 +241,13 @@ module ActiveRecord
241
241
  # The generated ID for a given label is constant, so we can discover
242
242
  # any fixture's ID without loading anything, as long as we know the label.
243
243
  #
244
- # == Label references for associations (belongs_to, has_one, has_many)
244
+ # == Label references for associations (+belongs_to+, +has_one+, +has_many+)
245
245
  #
246
246
  # Specifying foreign keys in fixtures can be very fragile, not to
247
247
  # mention difficult to read. Since Active Record can figure out the ID of
248
248
  # any fixture from its label, you can specify FK's by label instead of ID.
249
249
  #
250
- # === belongs_to
250
+ # === +belongs_to+
251
251
  #
252
252
  # Let's break out some more monkeys and pirates.
253
253
  #
@@ -286,7 +286,7 @@ module ActiveRecord
286
286
  # a target *label* for the *association* (monkey: george) rather than
287
287
  # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
288
288
  #
289
- # ==== Polymorphic belongs_to
289
+ # ==== Polymorphic +belongs_to+
290
290
  #
291
291
  # Supporting polymorphic relationships is a little bit more complicated, since
292
292
  # Active Record needs to know what type your association is pointing at. Something
@@ -311,7 +311,7 @@ module ActiveRecord
311
311
  #
312
312
  # Just provide the polymorphic target type and Active Record will take care of the rest.
313
313
  #
314
- # === has_and_belongs_to_many or has_many :through
314
+ # === +has_and_belongs_to_many+ or <tt>has_many :through</tt>
315
315
  #
316
316
  # Time to give our monkey some fruit.
317
317
  #
@@ -407,7 +407,7 @@ module ActiveRecord
407
407
  # defaults:
408
408
  #
409
409
  # DEFAULTS: &DEFAULTS
410
- # created_on: <%= 3.weeks.ago.to_formatted_s(:db) %>
410
+ # created_on: <%= 3.weeks.ago.to_fs(:db) %>
411
411
  #
412
412
  # first:
413
413
  # name: Smurf
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
4
+ # Returns the currently loaded version of Active Record as a <tt>Gem::Version</tt>.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 0
12
+ TINY = 4
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  timestamp = max_updated_column_timestamp
80
80
 
81
81
  if timestamp
82
- timestamp = timestamp.utc.to_formatted_s(cache_timestamp_format)
82
+ timestamp = timestamp.utc.to_fs(cache_timestamp_format)
83
83
  "#{model_name.cache_key}/#{id}-#{timestamp}"
84
84
  else
85
85
  "#{model_name.cache_key}/#{id}"
@@ -103,7 +103,7 @@ module ActiveRecord
103
103
  raw_timestamp_to_cache_version(timestamp)
104
104
 
105
105
  elsif timestamp = updated_at
106
- timestamp.utc.to_formatted_s(cache_timestamp_format)
106
+ timestamp.utc.to_fs(cache_timestamp_format)
107
107
  end
108
108
  elsif self.class.has_attribute?("updated_at")
109
109
  raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  # Locking::Pessimistic provides support for row-level locking using
6
6
  # SELECT ... FOR UPDATE and other lock types.
7
7
  #
8
- # Chain <tt>ActiveRecord::Base#find</tt> to <tt>ActiveRecord::QueryMethods#lock</tt> to obtain an exclusive
8
+ # Chain <tt>ActiveRecord::Base#find</tt> to ActiveRecord::QueryMethods#lock to obtain an exclusive
9
9
  # lock on the selected rows:
10
10
  # # select * from accounts where id=1 for update
11
11
  # Account.lock.find(1)
@@ -81,11 +81,11 @@ module ActiveRecord
81
81
 
82
82
  # Wraps the passed block in a transaction, locking the object
83
83
  # before yielding. You can pass the SQL locking clause
84
- # as an optional argument (see <tt>#lock!</tt>).
84
+ # as an optional argument (see #lock!).
85
85
  #
86
86
  # You can also pass options like <tt>requires_new:</tt>, <tt>isolation:</tt>,
87
87
  # and <tt>joinable:</tt> to the wrapping transaction (see
88
- # <tt>ActiveRecord::ConnectionAdapters::DatabaseStatements#transaction</tt>).
88
+ # ActiveRecord::ConnectionAdapters::DatabaseStatements#transaction).
89
89
  def with_lock(*args)
90
90
  transaction_opts = args.extract_options!
91
91
  lock = args.present? ? args.first : true