Merge branch 'main' into 43114-add-ssl-support-for-postgresql-dbconsole
This commit is contained in:
commit
32612c6d41
|
@ -1,3 +1,11 @@
|
|||
* Use a static error message when raising `ActionDispatch::Http::Parameters::ParseError`
|
||||
to avoid inadvertently logging the HTTP request body at the `fatal` level when it contains
|
||||
malformed JSON.
|
||||
|
||||
Fixes #41145
|
||||
|
||||
*Aaron Lahey*
|
||||
|
||||
* Add `Middleware#delete!` to delete middleware or raise if not found.
|
||||
|
||||
`Middleware#delete!` works just like `Middleware#delete` but will
|
||||
|
|
|
@ -17,8 +17,8 @@ module ActionDispatch
|
|||
# Raised when raw data from the request cannot be parsed by the parser
|
||||
# defined for request's content MIME type.
|
||||
class ParseError < StandardError
|
||||
def initialize
|
||||
super($!.message)
|
||||
def initialize(message = $!.message)
|
||||
super(message)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -93,7 +93,7 @@ module ActionDispatch
|
|||
strategy.call(raw_post)
|
||||
rescue # JSON or Ruby code block errors.
|
||||
log_parse_error_once
|
||||
raise ParseError
|
||||
raise ParseError, "Error occurred while parsing request parameters"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
|
|||
post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => false }
|
||||
end
|
||||
assert_equal JSON::ParserError, exception.cause.class
|
||||
assert_equal exception.cause.message, exception.message
|
||||
assert_equal "Error occurred while parsing request parameters", exception.message
|
||||
ensure
|
||||
$stderr = STDERR
|
||||
end
|
||||
|
|
|
@ -123,7 +123,7 @@ module ActiveModel
|
|||
# user.serializable_hash(include: { notes: { only: 'title' }})
|
||||
# # => {"name" => "Napoleon", "notes" => [{"title"=>"Battle of Austerlitz"}]}
|
||||
def serializable_hash(options = nil)
|
||||
attribute_names = attributes.keys
|
||||
attribute_names = self.attribute_names
|
||||
|
||||
return serializable_attributes(attribute_names) if options.blank?
|
||||
|
||||
|
@ -148,6 +148,11 @@ module ActiveModel
|
|||
hash
|
||||
end
|
||||
|
||||
# Returns an array of attribute names as strings
|
||||
def attribute_names # :nodoc:
|
||||
attributes.keys
|
||||
end
|
||||
|
||||
private
|
||||
# Hook method defining how an attribute value should be retrieved for
|
||||
# serialization. By default this is assumed to be an instance named after
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
* Make schema cache methods return consistent results.
|
||||
|
||||
Previously the schema cache methods `primary_keys`, `columns, `columns_hash`, and `indexes`
|
||||
Previously the schema cache methods `primary_keys`, `columns`, `columns_hash`, and `indexes`
|
||||
would behave differently than one another when a table didn't exist and differently across
|
||||
database adapters. This change unifies the behavior so each method behaves the same regardless
|
||||
of adapter.
|
||||
|
|
|
@ -196,14 +196,7 @@ module ActiveRecord
|
|||
|
||||
# Executes the SQL statement in the context of this connection.
|
||||
def execute(sql, name = nil, async: false)
|
||||
materialize_transactions
|
||||
mark_transaction_written_if_write(sql)
|
||||
|
||||
log(sql, name, async: async) do
|
||||
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
||||
@connection.query(sql)
|
||||
end
|
||||
end
|
||||
raw_execute(sql, name, async)
|
||||
end
|
||||
|
||||
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
||||
|
@ -629,6 +622,17 @@ module ActiveRecord
|
|||
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
||||
end
|
||||
|
||||
def raw_execute(sql, name, async: false)
|
||||
materialize_transactions
|
||||
mark_transaction_written_if_write(sql)
|
||||
|
||||
log(sql, name, async: async) do
|
||||
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
||||
@connection.query(sql)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
||||
ER_DB_CREATE_EXISTS = 1007
|
||||
ER_FILSORT_ABORT = 1028
|
||||
|
|
|
@ -37,25 +37,11 @@ module ActiveRecord
|
|||
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
||||
end
|
||||
|
||||
def execute(sql, name = nil, async: false)
|
||||
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
||||
# made since we established the connection
|
||||
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
||||
|
||||
super
|
||||
end
|
||||
alias_method :raw_execute, :execute
|
||||
private :raw_execute
|
||||
|
||||
# Executes the SQL statement in the context of this connection.
|
||||
def execute(sql, name = nil, async: false)
|
||||
sql = transform_query(sql)
|
||||
check_if_write_query(sql)
|
||||
|
||||
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
||||
# made since we established the connection
|
||||
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
||||
|
||||
raw_execute(sql, name, async: async)
|
||||
end
|
||||
|
||||
|
@ -91,6 +77,14 @@ module ActiveRecord
|
|||
alias :exec_update :exec_delete
|
||||
|
||||
private
|
||||
def raw_execute(sql, name, async: false)
|
||||
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
||||
# made since we established the connection
|
||||
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def execute_batch(statements, name = nil)
|
||||
statements = statements.map { |sql| transform_query(sql) }
|
||||
combine_multi_statements(statements).each do |statement|
|
||||
|
|
|
@ -17,7 +17,7 @@ require "models/hotel"
|
|||
require "models/department"
|
||||
|
||||
class HasManyThroughDisableJoinsAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :authors, :comments, :pirates
|
||||
fixtures :posts, :authors, :comments, :pirates, :author_addresses
|
||||
|
||||
def setup
|
||||
@author = authors(:mary)
|
||||
|
|
|
@ -5,7 +5,7 @@ require "models/author"
|
|||
|
||||
module ActiveRecord
|
||||
class AndTest < ActiveRecord::TestCase
|
||||
fixtures :authors
|
||||
fixtures :authors, :author_addresses
|
||||
|
||||
def test_and
|
||||
david, mary, bob = authors(:david, :mary, :bob)
|
||||
|
|
|
@ -10,7 +10,7 @@ require "models/categorization"
|
|||
|
||||
module ActiveRecord
|
||||
class WhereChainTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :comments, :authors, :humans, :essays
|
||||
fixtures :posts, :comments, :authors, :humans, :essays, :author_addresses
|
||||
|
||||
def test_associated_with_association
|
||||
Post.where.associated(:author).tap do |relation|
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
* Emit Active Support instrumentation events from Active Storage analyzers.
|
||||
|
||||
Fixes #42930
|
||||
|
||||
*Shouichi Kamiya*
|
||||
|
||||
* Add support for byte range requests
|
||||
|
||||
*Tom Prats*
|
||||
|
|
|
@ -40,5 +40,9 @@ module ActiveStorage
|
|||
def tmpdir # :doc:
|
||||
Dir.tmpdir
|
||||
end
|
||||
|
||||
def instrument(analyzer, &block) # :doc:
|
||||
ActiveSupport::Notifications.instrument("analyze.active_storage", analyzer: analyzer, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,14 +42,16 @@ module ActiveStorage
|
|||
end
|
||||
|
||||
def probe_from(file)
|
||||
IO.popen([ ffprobe_path,
|
||||
"-print_format", "json",
|
||||
"-show_streams",
|
||||
"-show_format",
|
||||
"-v", "error",
|
||||
file.path
|
||||
]) do |output|
|
||||
JSON.parse(output.read)
|
||||
instrument(File.basename(ffprobe_path)) do
|
||||
IO.popen([ ffprobe_path,
|
||||
"-print_format", "json",
|
||||
"-show_streams",
|
||||
"-show_format",
|
||||
"-v", "error",
|
||||
file.path
|
||||
]) do |output|
|
||||
JSON.parse(output.read)
|
||||
end
|
||||
end
|
||||
rescue Errno::ENOENT
|
||||
logger.info "Skipping audio analysis because FFmpeg isn't installed"
|
||||
|
|
|
@ -12,7 +12,10 @@ module ActiveStorage
|
|||
def read_image
|
||||
download_blob_to_tempfile do |file|
|
||||
require "mini_magick"
|
||||
image = MiniMagick::Image.new(file.path)
|
||||
|
||||
image = instrument("mini_magick") do
|
||||
MiniMagick::Image.new(file.path)
|
||||
end
|
||||
|
||||
if image.valid?
|
||||
yield image
|
||||
|
|
|
@ -12,7 +12,10 @@ module ActiveStorage
|
|||
def read_image
|
||||
download_blob_to_tempfile do |file|
|
||||
require "ruby-vips"
|
||||
image = ::Vips::Image.new_from_file(file.path, access: :sequential)
|
||||
|
||||
image = instrument("vips") do
|
||||
::Vips::Image.new_from_file(file.path, access: :sequential)
|
||||
end
|
||||
|
||||
if valid_image?(image)
|
||||
yield image
|
||||
|
|
|
@ -121,14 +121,16 @@ module ActiveStorage
|
|||
end
|
||||
|
||||
def probe_from(file)
|
||||
IO.popen([ ffprobe_path,
|
||||
"-print_format", "json",
|
||||
"-show_streams",
|
||||
"-show_format",
|
||||
"-v", "error",
|
||||
file.path
|
||||
]) do |output|
|
||||
JSON.parse(output.read)
|
||||
instrument(File.basename(ffprobe_path)) do
|
||||
IO.popen([ ffprobe_path,
|
||||
"-print_format", "json",
|
||||
"-show_streams",
|
||||
"-show_format",
|
||||
"-v", "error",
|
||||
file.path
|
||||
]) do |output|
|
||||
JSON.parse(output.read)
|
||||
end
|
||||
end
|
||||
rescue Errno::ENOENT
|
||||
logger.info "Skipping video analysis because FFmpeg isn't installed"
|
||||
|
|
|
@ -42,6 +42,9 @@ module ActiveStorage
|
|||
image/vnd.adobe.photoshop
|
||||
image/vnd.microsoft.icon
|
||||
image/webp
|
||||
image/avif
|
||||
image/heic
|
||||
image/heif
|
||||
)
|
||||
|
||||
config.active_storage.web_image_content_types = %w(
|
||||
|
|
|
@ -13,4 +13,14 @@ class ActiveStorage::Analyzer::AudioAnalyzerTest < ActiveSupport::TestCase
|
|||
assert_equal 0.914286, metadata[:duration]
|
||||
assert_equal 128000, metadata[:bit_rate]
|
||||
end
|
||||
|
||||
test "instrumenting analysis" do
|
||||
events = subscribe_events_from("analyze.active_storage")
|
||||
|
||||
blob = create_file_blob(filename: "audio.mp3", content_type: "audio/mp3")
|
||||
blob.analyze
|
||||
|
||||
assert_equal 1, events.size
|
||||
assert_equal({ analyzer: "ffprobe" }, events.first.payload)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,6 +46,18 @@ class ActiveStorage::Analyzer::ImageAnalyzer::ImageMagickTest < ActiveSupport::T
|
|||
end
|
||||
end
|
||||
|
||||
test "instrumenting analysis" do
|
||||
analyze_with_image_magick do
|
||||
events = subscribe_events_from("analyze.active_storage")
|
||||
|
||||
blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpeg")
|
||||
blob.analyze
|
||||
|
||||
assert_equal 1, events.size
|
||||
assert_equal({ analyzer: "mini_magick" }, events.first.payload)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def analyze_with_image_magick
|
||||
previous_processor, ActiveStorage.variant_processor = ActiveStorage.variant_processor, :mini_magick
|
||||
|
|
|
@ -46,6 +46,18 @@ class ActiveStorage::Analyzer::ImageAnalyzer::VipsTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
test "instrumenting analysis" do
|
||||
analyze_with_vips do
|
||||
events = subscribe_events_from("analyze.active_storage")
|
||||
|
||||
blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpeg")
|
||||
blob.analyze
|
||||
|
||||
assert_equal 1, events.size
|
||||
assert_equal({ analyzer: "vips" }, events.first.payload)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def analyze_with_vips
|
||||
previous_processor, ActiveStorage.variant_processor = ActiveStorage.variant_processor, :vips
|
||||
|
|
|
@ -76,4 +76,14 @@ class ActiveStorage::Analyzer::VideoAnalyzerTest < ActiveSupport::TestCase
|
|||
assert metadata[:video]
|
||||
assert_not metadata[:audio]
|
||||
end
|
||||
|
||||
test "instrumenting analysis" do
|
||||
events = subscribe_events_from("analyze.active_storage")
|
||||
|
||||
blob = create_file_blob(filename: "video_without_audio_stream.mp4", content_type: "video/mp4")
|
||||
blob.analyze
|
||||
|
||||
assert_equal 1, events.size
|
||||
assert_equal({ analyzer: "ffprobe" }, events.first.payload)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -157,6 +157,14 @@ class ActiveSupport::TestCase
|
|||
ActionController::Base.raise_on_open_redirects = old_raise_on_open_redirects
|
||||
ActiveStorage::Blob.service = old_service
|
||||
end
|
||||
|
||||
def subscribe_events_from(name)
|
||||
events = []
|
||||
ActiveSupport::Notifications.subscribe(name) do |*args|
|
||||
events << ActiveSupport::Notifications::Event.new(*args)
|
||||
end
|
||||
events
|
||||
end
|
||||
end
|
||||
|
||||
require "global_id"
|
||||
|
|
|
@ -17,7 +17,7 @@ After reading this guide you will know:
|
|||
|
||||
Active Record supports application-level encryption. It works by declaring which attributes should be encrypted and seamlessly encrypting and decrypting them when necessary. The encryption layer is placed between the database and the application. The application will access unencrypted data but the database will store it encrypted.
|
||||
|
||||
## Basic usage
|
||||
## Basic Usage
|
||||
|
||||
### Setup
|
||||
|
||||
|
@ -35,7 +35,7 @@ active_record_encryption:
|
|||
|
||||
NOTE: These generated keys and salt are 32 bytes length. If you generate these yourself, the minimum lengths you should use are 12 bytes for the primary key (this will be used to derive the AES 32 bytes key) and 20 bytes for the salt.
|
||||
|
||||
### Declaration of encrypted attributes
|
||||
### Declaration of Encrypted Attributes
|
||||
|
||||
Encryptable attributes are defined at the model level. These are regular Active Record attributes backed by a column with the same name.
|
||||
|
||||
|
@ -62,7 +62,7 @@ Encryption takes additional space in the column. You can estimate the worst-case
|
|||
|
||||
NOTE: The reason for the additional space are Base 64 encoding and additional metadata stored with the encrypted values.
|
||||
|
||||
### Deterministic and non-deterministic encryption
|
||||
### Deterministic and Non-deterministic Encryption
|
||||
|
||||
By default, Active Record Encryption uses a non-deterministic approach to encryption. This means that encrypting the same content with the same password twice will result in different ciphertexts. This is good for security, since it makes crypto-analysis of encrypted content much harder, but it makes querying the database impossible.
|
||||
|
||||
|
@ -106,11 +106,11 @@ config.active_record.encryption.encrypt_fixtures = true
|
|||
|
||||
When enabled, all the encryptable attributes will be encrypted according to the encryption settings defined in the model.
|
||||
|
||||
#### Action text fixtures
|
||||
#### Action Text Fixtures
|
||||
|
||||
To encrypt action text fixtures you should place them in `fixtures/action_text/encrypted_rich_texts.yml`.
|
||||
|
||||
### Supported types
|
||||
### Supported Types
|
||||
|
||||
`active_record.encryption` will serialize values using the underlying type before encrypting them, but *they must be serializable as strings*. Structured types like `serialized` are supported out of the box.
|
||||
|
||||
|
@ -130,7 +130,7 @@ class Article < ApplicationRecord
|
|||
end
|
||||
```
|
||||
|
||||
### Ignoring case
|
||||
### Ignoring Case
|
||||
|
||||
You might need to ignore case when querying deterministically encrypted data. There are two options that can help you here.
|
||||
|
||||
|
@ -150,7 +150,7 @@ class Label
|
|||
end
|
||||
```
|
||||
|
||||
### Support for unencrypted data
|
||||
### Support for Unencrypted Data
|
||||
|
||||
To ease migrations of unencrypted data, the library includes the option `config.active_record.encryption.support_unencrypted_data`. When set to `true`:
|
||||
|
||||
|
@ -159,7 +159,7 @@ To ease migrations of unencrypted data, the library includes the option `config.
|
|||
|
||||
**This options is meant to be used in transition periods** while clear data and encrypted data need to coexist. Their value is `false` by default, which is the recommended goal for any application: errors will be raised when working with unencrypted data.
|
||||
|
||||
### Support for previous encryption schemes
|
||||
### Support for Previous Encryption Schemes
|
||||
|
||||
Changing encryption properties of attributes can break existing data. For example, imagine you want to make a "deterministic" attribute "not deterministic". If you just change the declaration in the model, reading existing ciphertexts will fail because they are different now.
|
||||
|
||||
|
@ -173,7 +173,7 @@ You can configure previous encryption schemes:
|
|||
* Globally
|
||||
* On a per-attribute basis
|
||||
|
||||
#### Global previous encryption schemes
|
||||
#### Global Previous Encryption Schemes
|
||||
|
||||
You can add previous encryption schemes by adding them as list of properties using the `previous` config property in your `application.rb`:
|
||||
|
||||
|
@ -181,7 +181,7 @@ You can add previous encryption schemes by adding them as list of properties usi
|
|||
config.active_record.encryption.previous = [ { key_provider: MyOldKeyProvider.new } ]
|
||||
```
|
||||
|
||||
#### Per-attribute encryption schemes
|
||||
#### Per-attribute Encryption Schemes
|
||||
|
||||
Use `:previous` when declaring the attribute:
|
||||
|
||||
|
@ -191,7 +191,7 @@ class Article
|
|||
end
|
||||
```
|
||||
|
||||
#### Encryption schemes and deterministic attributes
|
||||
#### Encryption Schemes and Deterministic Attributes
|
||||
|
||||
When adding previous encryption schemes:
|
||||
|
||||
|
@ -200,11 +200,11 @@ When adding previous encryption schemes:
|
|||
|
||||
The reason is that, with deterministic encryption, you normally want ciphertexts to remain constant. You can change this behavior by setting `deterministic: { fixed: false }`. In that case, it will use the *newest* encryption scheme for encrypting new data.
|
||||
|
||||
### Unique constraints
|
||||
### Unique Constraints
|
||||
|
||||
NOTE: Unique constraints can only be used with data encrypted deterministically.
|
||||
|
||||
#### Unique validations
|
||||
#### Unique Validations
|
||||
|
||||
Unique validations are supported normally as long as extended queries are enabled (`config.active_record.encryption.extend_queries = true`).
|
||||
|
||||
|
@ -219,7 +219,7 @@ They will also work when combining encrypted and unencrypted data, and when conf
|
|||
|
||||
NOTE: If you want to ignore case make sure to use `downcase:` or `ignore_case:` in the `encrypts` declaration. Using the `case_sensitive:` option in the validation won't work.
|
||||
|
||||
#### Unique indexes
|
||||
#### Unique Indexes
|
||||
|
||||
To support unique indexes on deterministically-encrypted columns, you need to make sure their ciphertext doesn't ever change.
|
||||
|
||||
|
@ -231,7 +231,7 @@ class Person
|
|||
end
|
||||
```
|
||||
|
||||
### Filtering params named as encrypted columns
|
||||
### Filtering Params Named as Encrypted Columns
|
||||
|
||||
By default, encrypted columns are configured to be [automatically filtered in Rails logs](https://guides.rubyonrails.org/action_controller_overview.html#parameters-filtering). You can disable this behavior by adding this to your `application.rb`:
|
||||
|
||||
|
@ -258,11 +258,11 @@ And you can disable this behavior and preserve the encoding in all cases with:
|
|||
config.active_record.encryption.forced_encoding_for_deterministic_encryption = nil
|
||||
```
|
||||
|
||||
## Key management
|
||||
## Key Management
|
||||
|
||||
Key management strategies are implemented by key providers. You can configure key providers globally or on a per-attribute basis.
|
||||
|
||||
### Built-in key providers
|
||||
### Built-in Key Providers
|
||||
|
||||
#### DerivedSecretKeyProvider
|
||||
|
||||
|
@ -289,7 +289,7 @@ config.active_record.encryption.key_provider = ActiveRecord::Encryption::Envelop
|
|||
|
||||
As with other built-in key providers, you can provide a list of primary keys in `active_record.encryption.primary_key`, to implement key-rotation schemes.
|
||||
|
||||
### Custom key providers
|
||||
### Custom Key Providers
|
||||
|
||||
For more advanced key-management schemes, you can configure a custom key provider in an initializer:
|
||||
|
||||
|
@ -316,7 +316,7 @@ Both methods return `ActiveRecord::Encryption::Key` objects:
|
|||
|
||||
A key can include arbitrary tags that will be stored unencrypted with the message. You can use `ActiveRecord::Encryption::Message#headers` to examine those values when decrypting.
|
||||
|
||||
### Model-specific key providers
|
||||
### Model-specific Key Providers
|
||||
|
||||
You can configure a key provider on a per-class basis with the `:key_provider` option:
|
||||
|
||||
|
@ -326,7 +326,7 @@ class Article < ApplicationRecord
|
|||
end
|
||||
```
|
||||
|
||||
### Model-specific keys
|
||||
### Model-specific Keys
|
||||
|
||||
You can configure a given key on a per-class basis with the `:key` option:
|
||||
|
||||
|
@ -338,7 +338,7 @@ end
|
|||
|
||||
The key will be used internally to derive the key used to encrypt and decrypt the data.
|
||||
|
||||
### Rotating keys
|
||||
### Rotating Keys
|
||||
|
||||
`active_record.encryption` can work with lists of keys to support implementing key-rotation schemes:
|
||||
|
||||
|
@ -360,7 +360,7 @@ NOTE: Rotating keys is not currently supported for deterministic encryption.
|
|||
|
||||
NOTE: Active Record Encryption doesn't provide automatic management of key rotation processes yet. All the pieces are there, but this hasn't been implemented yet.
|
||||
|
||||
### Storing key references
|
||||
### Storing Key References
|
||||
|
||||
There is a setting `active_record.encryption.store_key_references` you can use to make `active_record.encryption` store a reference to the encryption key in the encrypted message itself.
|
||||
|
||||
|
@ -376,20 +376,20 @@ This makes for a more performant decryption since, instead of trying lists of ke
|
|||
|
||||
ActiveRecord encryption is meant to be used declaratively, but it presents an API for advanced usage scenarios.
|
||||
|
||||
#### Encrypt and decrypt
|
||||
#### Encrypt and Decrypt
|
||||
|
||||
```ruby
|
||||
article.encrypt # encrypt or re-encrypt all the encryptable attributes
|
||||
article.decrypt # decrypt all the encryptable attributes
|
||||
```
|
||||
|
||||
#### Read ciphertext
|
||||
#### Read Ciphertext
|
||||
|
||||
```ruby
|
||||
article.ciphertext_for(:title)
|
||||
```
|
||||
|
||||
#### Check if attribute is encrypted or not
|
||||
#### Check if Attribute is Encrypted or Not
|
||||
|
||||
```ruby
|
||||
article.encrypted_attribute?(:title)
|
||||
|
@ -397,7 +397,7 @@ article.encrypted_attribute?(:title)
|
|||
|
||||
## Configuration
|
||||
|
||||
### Configuration options
|
||||
### Configuration Options
|
||||
|
||||
You can configure Active Record Encryption options by setting them in your `application.rb` (most common scenario) or in a specific environment config file `config/environments/<env name>.rb` if you want to set them on a per-environment basis.
|
||||
|
||||
|
@ -426,7 +426,7 @@ The available config options are:
|
|||
|
||||
NOTE: It's recommended to use Rails built-in credentials support to store keys. If you prefer to set them manually via config properties, make sure you don't commit them with your code (e.g: use environment variables).
|
||||
|
||||
### Encryption contexts
|
||||
### Encryption Contexts
|
||||
|
||||
An encryption context defines the encryption components that are used in a given moment. There is a default encryption context based on your global configuration, but you can configure a custom context for a given attribute or when running a specific block of code.
|
||||
|
||||
|
@ -441,7 +441,7 @@ The main components of encryption contexts are:
|
|||
|
||||
NOTE: If you decide to build your own `message_serializer`, It's important to use safe mechanisms that can't deserialize arbitrary objects. A common supported scenario is encrypting existing unencrypted data. An attacker can leverage this to enter a tampered payload before encryption takes place and perform RCE attacks. This means custom serializers should avoid `Marshal`, `YAML.load` (use `YAML.safe_load` instead) or `JSON.load` (use `JSON.parse` instead).
|
||||
|
||||
#### Global encryption context
|
||||
#### Global Encryption Context
|
||||
|
||||
The global encryption context is the one used by default and is configured as other configuration properties in your `application.rb` or environment config files.
|
||||
|
||||
|
@ -450,7 +450,7 @@ config.active_record.encryption.key_provider = ActiveRecord::Encryption::Envelop
|
|||
config.active_record_encryption.encryptor = MyEncryptor.new
|
||||
```
|
||||
|
||||
#### Per-attribute encryption contexts
|
||||
#### Per-attribute Encryption Contexts
|
||||
|
||||
You can override encryption context params by passing them in the attribute declaration:
|
||||
|
||||
|
@ -460,7 +460,7 @@ class Attribute
|
|||
end
|
||||
```
|
||||
|
||||
#### Encryption context when running a block of code
|
||||
#### Encryption Context When Running a Block of Code
|
||||
|
||||
You can use `ActiveRecord::Encryption.with_encryption_context` to set an encryption context for a given block of code:
|
||||
|
||||
|
@ -470,9 +470,9 @@ ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryp
|
|||
end
|
||||
```
|
||||
|
||||
#### Built-in encryption contexts
|
||||
#### Built-in Encryption Contexts
|
||||
|
||||
##### Disable encryption
|
||||
##### Disable Encryption
|
||||
|
||||
You can run code without encryption:
|
||||
|
||||
|
@ -483,7 +483,7 @@ end
|
|||
```
|
||||
This means that reading encrypted text will return the ciphertext and saved content will be stored unencrypted.
|
||||
|
||||
##### Protect encrypted data
|
||||
##### Protect Encrypted Data
|
||||
|
||||
You can run code without encryption but preventing overwriting encrypted content:
|
||||
|
||||
|
|
|
@ -690,6 +690,12 @@ INFO. The only ActiveStorage service that provides this hook so far is GCS.
|
|||
|
||||
#### transform.active_storage
|
||||
|
||||
#### analyze.active_storage
|
||||
|
||||
| Key | Value |
|
||||
| ------------ | ------------------------------ |
|
||||
| `:analyzer` | Name of analyzer e.g., ffprobe |
|
||||
|
||||
### Railties
|
||||
|
||||
#### load_config_initializer.railties
|
||||
|
|
|
@ -517,6 +517,9 @@ in controllers and views. This defaults to `false`.
|
|||
the context does not change during the lifetime of the request or job execution.
|
||||
Defaults to `false`.
|
||||
|
||||
* `config.active_record.schema_cache_ignored_tables` define the list of table that should be ignored when generating
|
||||
the schema cache. It accepts an `Array` of strings, representing the table names, or regular expressions.
|
||||
|
||||
The MySQL adapter adds one additional configuration option:
|
||||
|
||||
* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`.
|
||||
|
@ -1047,9 +1050,9 @@ You can find more detailed configuration options in the
|
|||
config.active_storage.paths[:ffprobe] = '/usr/local/bin/ffprobe'
|
||||
```
|
||||
|
||||
* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/pjpeg image/tiff image/bmp image/vnd.adobe.photoshop image/vnd.microsoft.icon image/webp)`.
|
||||
* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/pjpeg image/tiff image/bmp image/vnd.adobe.photoshop image/vnd.microsoft.icon image/webp image/avif image/heic image/heif)`.
|
||||
|
||||
* `config.active_storage.web_image_content_types` accepts an array of strings regarded as web image content types in which variants can be processed without being converted to the fallback PNG format. If you want to use `WebP` variants in your application you can add `image/webp` to this array. The default is `%w(image/png image/jpeg image/jpg image/gif)`.
|
||||
* `config.active_storage.web_image_content_types` accepts an array of strings regarded as web image content types in which variants can be processed without being converted to the fallback PNG format. If you want to use `WebP` or `AVIF` variants in your application you can add `image/webp` or `image/avif` to this array. The default is `%w(image/png image/jpeg image/jpg image/gif)`.
|
||||
|
||||
* `config.active_storage.content_types_to_serve_as_binary` accepts an array of strings indicating the content types that Active Storage will always serve as an attachment, rather than inline. The default is `%w(text/html
|
||||
text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml application/mathml+xml text/cache-manifest)`.
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
*Michael Bayucot*
|
||||
|
||||
* Add support for comments above gem declaration in Rails application templates, e.g. `gem("nokogiri", comment: "For XML")`.
|
||||
|
||||
*Linas Juškevičius*
|
||||
|
||||
* The setter `config.autoloader=` has been deleted. `zeitwerk` is the only
|
||||
available autoloading mode.
|
||||
|
||||
|
@ -28,7 +32,7 @@
|
|||
railties initializers.
|
||||
|
||||
Please check the [autoloading
|
||||
guide](https://edgeguides.rubyonrails.org/autoloading_and_reloading_constants.html#autoloading-when-the-application-boots)
|
||||
guide](https://guides.rubyonrails.org/v7.0/autoloading_and_reloading_constants.html#autoloading-when-the-application-boots)
|
||||
for details.
|
||||
|
||||
*Xavier Noria*
|
||||
|
@ -40,9 +44,9 @@
|
|||
|
||||
*Xavier Noria*
|
||||
|
||||
* Show Rake task description if command is run with -h.
|
||||
* Show Rake task description if command is run with `-h`.
|
||||
|
||||
Adding `-h` (or `--help`) to a Rails command that's a Rake task, now returns
|
||||
Adding `-h` (or `--help`) to a Rails command that's a Rake task now outputs
|
||||
the task description instead of the general Rake help.
|
||||
|
||||
*Petrik de Heus*
|
||||
|
@ -94,7 +98,7 @@
|
|||
|
||||
*Jean Boussier*
|
||||
|
||||
* Remove Rack::Runtime from the default middleware stack and deprecate
|
||||
* Remove `Rack::Runtime` from the default middleware stack and deprecate
|
||||
referencing it in middleware operations without adding it back.
|
||||
|
||||
*Hartley McGuire*
|
||||
|
@ -121,20 +125,17 @@
|
|||
|
||||
*Prateek Choudhary*
|
||||
|
||||
* Add benchmark method that can be called from anywhere.
|
||||
* The new method `Rails.benchmark` gives you a quick way to measure and log the execution time taken by a block:
|
||||
|
||||
This method is used as a quick way to measure & log the speed of some code.
|
||||
However, it was previously available only in specific contexts, mainly views and controllers.
|
||||
The new Rails.benchmark can be used in the rest of your app: services, API wrappers, models, etc.
|
||||
|
||||
def test
|
||||
Rails.benchmark("test") { ... }
|
||||
def test_expensive_stuff
|
||||
Rails.benchmark("test_expensive_stuff") { ... }
|
||||
end
|
||||
|
||||
This functionality was available in some contexts only before.
|
||||
|
||||
*Simon Perepelitsa*
|
||||
|
||||
* Removed manifest.js and application.css in app/assets
|
||||
folder when --skip-sprockets option passed as flag to rails.
|
||||
* Applications generated with `--skip-sprockets` no longer get `app/assets/config/manifest.js` and `app/assets/stylesheets/application.css`.
|
||||
|
||||
*Cindy Gao*
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ module Rails
|
|||
# gem "technoweenie-restful-authentication", lib: "restful-authentication", source: "http://gems.github.com/"
|
||||
# gem "rails", "3.0", git: "https://github.com/rails/rails"
|
||||
# gem "RedCloth", ">= 4.1.0", "< 4.2.0"
|
||||
# gem "rspec", comment: "Put this comment above the gem declaration"
|
||||
def gem(*args)
|
||||
options = args.extract_options!
|
||||
name, *versions = args
|
||||
|
@ -26,6 +27,9 @@ module Rails
|
|||
# otherwise use name (version).
|
||||
parts, message = [ quote(name) ], name.dup
|
||||
|
||||
# Output a comment above the gem declaration.
|
||||
comment = options.delete(:comment)
|
||||
|
||||
if versions = versions.any? ? versions : options.delete(:version)
|
||||
_versions = Array(versions)
|
||||
_versions.each do |version|
|
||||
|
@ -40,9 +44,17 @@ module Rails
|
|||
parts << quote(options) unless options.empty?
|
||||
|
||||
in_root do
|
||||
str = "gem #{parts.join(", ")}"
|
||||
str = indentation + str
|
||||
append_file_with_newline "Gemfile", str, verbose: false
|
||||
str = []
|
||||
if comment
|
||||
comment.each_line do |comment_line|
|
||||
str << indentation
|
||||
str << "# #{comment_line}"
|
||||
end
|
||||
str << "\n"
|
||||
end
|
||||
str << indentation
|
||||
str << "gem #{parts.join(", ")}"
|
||||
append_file_with_newline "Gemfile", str.join, verbose: false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -116,6 +116,22 @@ class ActionsTest < Rails::Generators::TestCase
|
|||
assert_file "Gemfile", /gem "rspec", github: "dchelimsky\/rspec", tag: "1\.2\.9\.rc1"/
|
||||
end
|
||||
|
||||
def test_gem_should_put_the_comment_before_gem_declaration
|
||||
run_generator
|
||||
|
||||
action :gem, "rspec", comment: "Use RSpec"
|
||||
|
||||
assert_file "Gemfile", /# Use RSpec\ngem "rspec"/
|
||||
end
|
||||
|
||||
def test_gem_should_support_multiline_comments
|
||||
run_generator
|
||||
|
||||
action :gem, "rspec", comment: "Use RSpec\nReplaces minitest"
|
||||
|
||||
assert_file "Gemfile", /# Use RSpec\n# Replaces minitest\ngem "rspec"/
|
||||
end
|
||||
|
||||
def test_gem_with_non_string_options
|
||||
run_generator
|
||||
|
||||
|
@ -156,6 +172,26 @@ class ActionsTest < Rails::Generators::TestCase
|
|||
assert_file "Gemfile", /\n\ngroup :development, :test do\n gem "rspec-rails"\nend\n\ngroup :test do\n gem "fakeweb"\nend\n\z/
|
||||
end
|
||||
|
||||
def test_gem_group_should_indent_comments
|
||||
run_generator
|
||||
|
||||
action :gem_group, :test do
|
||||
gem "fakeweb", comment: "Fake requests"
|
||||
end
|
||||
|
||||
assert_file "Gemfile", /\n\ngroup :test do\n # Fake requests\n gem "fakeweb"\nend\n\z/
|
||||
end
|
||||
|
||||
def test_gem_group_should_indent_multiline_comments
|
||||
run_generator
|
||||
|
||||
action :gem_group, :test do
|
||||
gem "fakeweb", comment: "Fake requests\nNeeded in tests"
|
||||
end
|
||||
|
||||
assert_file "Gemfile", /\n\ngroup :test do\n # Fake requests\n # Needed in tests\n gem "fakeweb"\nend\n\z/
|
||||
end
|
||||
|
||||
def test_github_should_create_an_indented_block
|
||||
run_generator
|
||||
|
||||
|
|
Loading…
Reference in New Issue