Commit Graph

2637 Commits

Author SHA1 Message Date
Rafael Mendonça França 2af68b257f
Remove deprecated `Rails.application.config.active_record.suppress_multiple_database_warning` 2024-02-20 21:39:06 +00:00
Donal McBreen 50e322962b
Add MessagePackMessageSerializer for binary data (#51102) 2024-02-16 09:07:25 -08:00
Donal McBreen 7d4a39cc6f
Support encrypting binary columns (#50920)
* Support encrypting binary columns

ActiveRecord Encryption doesn't prevent you from encrypting binary
columns but it doesn't have proper support for it either.

When the data is fed through encrypt/decrypt it is converted to a
String. This means that the the encryption layer is not transparent
to binary data - which should be passed as Type::Binary::Data.

As a result the data is not properly escaped in the SQL queries or
deserialized correctly after decryption.

However it just happens to work fine for MySQL and SQLite because the
MessageSerializer doesn't use any characters that need to be encoded.
However if you try to use a custom serializer that does then it breaks.

PostgreSQL on the other hand does not work - because the Bytea type
is passed a String rather than a Type::Binary::Data to deserialize, it
attempts to unescape the data and either mangles it or raises an error
if it contains null bytes.

The commit fixes the issue, by reserializing the data after
encryption and decryption. For text data that's a no-op, but for binary
data we'll convert it back to a Type::Binary::Data.

* Extract decrypt_as_text/encrypt_as_text

* Handle serialized binary data in encrypted columns

Calling `serialize` is not always possible, because the column type
might not expect to be serializing a String, for example when declared
as serialzed or store attribute.

With binary data the encryptor was passed an
`ActiveModel::Type::Binary::Data`` and returned a `String``. In order to
remain transparent we need to turn the data back into a
`ActiveModel::Type::Binary::Data` before passing it on.

We'll also rename `serialize`` to `text_to_database_type` to be a bit
more descriptive.
2024-02-15 08:45:56 -08:00
Rafael Mendonça França f91cb4f81f
Deprecated `ENV["SCHEMA_CACHE"]` in favor of `schema_cache_path` in the databse configuration
The config in the yaml allows for more complex configuration.
2024-02-14 22:02:29 +00:00
Jean Boussier 22f41a1b40 Add `ActiveRecord::Base.with_connection` as a shortcut
Extracted from https://github.com/rails/rails/pull/50793

The leased connection is yielded, and for the duration of the block,
any call to `ActiveRecord::Base.connection` will yield that same connection.

This is useful to perform a few database operations without causing a
connection to be leased for the entire duration of the request or job.
2024-02-14 14:07:04 +01:00
Jason Nochlin fc9ed119c7
Deprecate config.active_record.warn_on_records_fetched_greater_than (#51007)
* Deprecate config.active_record.warn_on_records_fetched_greater_than

* Review changes

Co-authored-by: Rafael Mendonça França <rafael@franca.dev>

---------

Co-authored-by: Jason Nochlin <hundredwatt@users.noreply.github.com>
Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
2024-02-13 18:20:55 -05:00
maximerety d997c554b3
[Fix #50604] Restore compatibility of ARE configs with eager loading mode
Configure ActiveRecord::Encryption (ARE) on ActiveRecord::Base (AR)
loading, so that ARE configs are ready before AR models start using
`encrypts` to declare encrypted attributes.

This means that you can add ARE configurations in initializers, as long
as you don't trigger the loading of ActiveRecord::Base or your AR models
in prior initializers.
2024-02-12 17:57:56 +01:00
Hartley McGuire 8c5425197c
Deprecate defining enums with keywords args
Enums have historically been defined using keyword arguments:

```ruby
class Function > ApplicationRecord
  enum color: [:red, :blue],
       type: [:instance, :class],
       _scopes: false
```

This has the advantage of being able to define multiple enums at once
with the same options. However, it also has a downside that enum options
must be prefixed with an underscore to separate them from the enum
definitions (to enable models to have enums with the same name as an
option).

In Rails 7, a new syntax was [introduced][1] to instead define enums with
positional arguments:

```ruby
class Function > ApplicationRecord
  enum :color, [:red, :blue], scopes: false
  enum :type, [:instance, :class], scopes: false
```

This new syntax eliminates the need to prefix options with an underscore,
and the docs were updated to recommend this new syntax.

However, both versions of the API have been supported since, and it has
started to cause some problems:

The first issue is that the available options have drifted. In Rails
7.1, an option was added to make assigning an invalid enum value use
validation errors instead of runtime errors. However, the equivalent
underscored prefix option was not added for the original enum syntax

Articles have been created that describe the new option in Rails 7.1,
but the examples in the articles use un-prefixed options with the old
syntax. This confusion has also lead to issues opened asking why that
incorrect syntax is not working.

Additionally, the presence of underscored options is just generally
confusing because it tends to imply an option is for internal use.

This commit aims to fix all of these issues by deprecating the old enum
syntax. With only one way to define enums, options cannot drift and
there will be less confusion around how enums should be defined.

[1]: 0618d2d84a
2024-02-10 00:20:45 +00:00
Adrianna Chang 06b7e345af
Add `active_record.config.validate_migration_timestamps` config option.
When set, an `ActiveRecord::InvalidMigrationTimestampError` will be raised if the timestamp
prefix for a migration is more than a day ahead of the timestamp associated with the current time.
This is done to prevent forward-dating of migration files, which can impact migration generation
and other migration commands.

It is turned off by default, but will be turned on for applications starting in Rails 7.2.
2024-02-08 12:14:26 -05:00
Jean Boussier 6f3b46b02d Properly synchronize `Mysql2Adapter#active?` and `TrilogyAdapter#active?`
As well as `disconnect!` and `verify!`.

This generally isn't a big problem as connections must not be shared between
threads, but is required when running transactional tests or system tests
and could lead to a SEGV.
2024-02-08 15:01:26 +01:00
fatkodima a87668a238 Support `:source_location` tag option for query log tags 2024-02-06 00:52:57 +02:00
Donal McBreen 8c3d4f2b24
Allow encryption without compression
Add a `compress` option to ActiveRecord::Encryption::Encryptor, which
defaults to `true`. When set to `false`, the encryptor will never
compress the data.

This is useful for cases where the data is already compressed.

This can be used with the `encryptor` option in the model:

```ruby
class Record < ApplicationRecord
  encrypts :field, encryptor: ActiveRecord::Encryption::Encryptor.new(compress: false)
end
```
2024-01-29 18:50:46 +00:00
Rafael Mendonça França 1cf7025b4d
Allow passing a DatabaseConfig object to cache_dump_filename 2024-01-29 18:18:13 +00:00
Marvin Bitterlich e9a2288c13
Add row_count field to sql.active_record notification
This field returns the amount of rows returned by the query that emitted the notification.    
This metric is useful in cases where one wants to detect queries with big result sets.
2024-01-27 00:12:19 +00:00
Joshua Young 1eab83a0a8 [Fix #50803] Consistently raise an `ArgumentError` when passing an invalid argument to a nested attributes association writer 2024-01-19 20:34:33 +10:00
Yash Kapadia 0702c24e7b Fix single quote escapes on default generated MySQL columns
MySQL 5.7.5+ supports generated columns, which can be used to create a column that is computed from an expression. This commit fixes the escaping of the default value for such expressions if a single quote is included.

See the following for more: https://dev.mysql.com/blog-archive/generated-columns-in-mysql-5-7-5/
2024-01-17 07:12:27 -05:00
Hartley McGuire 327f28b65f
Fix t.references validating options on Rails < 7.1
Option validation was [added][1] for 7.1+ Migration classes, and a
compatibility layer was added to ensure that previous Migration versions
do not have their options validated. However, the `t.references` method
was missing in the compatibility layer which results in pre 7.1
Migrations validating options passed to `t.references`.

This commit fixes the issue by adding t.references to the compatibility
layer.

See also a [similar fix][2] for `add_reference`

[1]: e6da3ebd6c
[2]: 71b4e22301
2024-01-16 17:21:22 -05:00
Hartley McGuire 71b4e22301
Fix add_reference options validated on < 7.1
Option validation was [added][1] for 7.1+ Migration classes, and
a compatibility layer was added to ensure that previous Migration
versions do not have their options validated. However, the add_reference
method was missing in the compatibility layer which results in pre 7.1
Migrations validating options passed to add_reference.

This commit fixes the issue by adding add_reference to the compatibility
layer. In addition to adding add_reference to the "no validation"
compatibility test, the test is refactored to run against each previous
migration version to ensure that they all behave consistently.

[1]: e6da3ebd6c
2024-01-15 20:52:49 +00:00
JP Rosevear b3fecab5c0
Merge branch 'main' into feature/delegated-type-types-introspection 2024-01-15 12:46:59 -05:00
Jean Boussier 63631e2d5b Make `schema_dump`, `query_cache`, `replica` and `database_tasks` configurable via `DATABASE_URL`
Fix: https://github.com/rails/rails/pull/50745

I went a bit farther and handled all the boolean configs, not just `schema_cache`.

Co-Authored-By: Mike Coutermarsh <coutermarsh.mike@gmail.com>
2024-01-15 15:51:31 +01:00
Joshua Young 93f068790a Fix [#50260] Support `:on` option in `#set_callback` 2024-01-12 12:30:13 +01:00
JP Rosevear e323d3f81c Define a class method to introspect valid delegatable types so they can
be used to validate the type column and power strong parameters.
2024-01-08 20:47:16 -05:00
maximerety d0f3b007b2
[Fix #48685] Make the encryptor agnostic of the type of data to decrypt
It is the role of the underlying serializer to accept or reject the data
to decrypt depending on its type. This behavior mirrors what is done at
encryption, where the serializer asserts that the input is an
ActiveRecord::Encryption::Message.

This change allows for a wider variety of custom serializers, but does
not change the behavior when using the default MessageSerializer class.
Indeed, the default message serializer will raise a TypeError when
invoking JSON.parse on any non-String input. This error will subsequently
be translated into an ActiveRecord::Encryption::Errors::Encoding error
by the encryptor, which does not change the current behavior at the
encryptor level.

A new test asserts that the default MessageSerializer is able to reject
unexpected data types on its own at decryption time, just as it does at
encryption time (test already present). The test also asserts that an
exception is translated into an ActiveRecord::Encryption::Error::Encoding
error at the encryptor level.
2024-01-05 13:05:15 -05:00
maximerety e7432ae5bb
[Fix #48922] Use context from the encrypted attribute type in encrypted_attribute?
Also fix implementation of TestEncryptor#encrypted?

The assertions fail because encrypted_attribute? delegates a decryption
attempt to the default encryptor (instead of the one configured) to
check if the value is actually encrypted.
2024-01-05 18:07:49 +01:00
Xavier Noria 1b56816bd6 Adds missing comma 2024-01-05 17:44:35 +01:00
Xavier Noria 6ca3a2ea4f Edit pass over the CHANGELOG of Active Record
Adds missing punctuation, revises grammar, updates typography, etc.

This follows our documentation guidelines, and makes the CHANGELOG
consistent in style.
2024-01-05 17:42:27 +01:00
Xavier Noria 6ab1c85dc0 Rewords a CHANGELOG entry
As discussed in #50599.
2024-01-05 17:13:01 +01:00
Petrik 2e2fb81503 Name all supported methods in `explain` CHANGELOG entry 2024-01-05 14:59:23 +01:00
Petrik 1f83af3890 Add `explain` support for methods like `last`, `pluck` and `count`
`explain` can be called on a relation to explain how the database would
execute a query. Currently `explain` doesn't work for queries using
`last`, `pluck` or `count`, as these return the actual result instead of
a relation. This makes it difficult to optimize these queries.

By letting `explain` return a proxy instead, we can support these
methods.

```ruby
User.all.explain.count
\# => "EXPLAIN SELECT COUNT(*) FROM `users`"

User.all.explain.maximum(:id)
\# => "EXPLAIN SELECT MAX(`users`.`id`) FROM `users`"
```

This breaks the existing behaviour in that it requires calling inspect
after explain.

```ruby
User.all.explain.inspect
\# => "EXPLAIN SELECT `users`.* FROM `users`"
```

However, as `explain` is mostly used from the commandline, this won't be a
problem as inspect is called automatically in IRB.

Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
2024-01-04 11:11:09 +01:00
Austen Madden e1e798142d Pass validation_context to validates_associated
The docs imply that when specified the `on` option of
`validates_associated` should be respected by the validated association.
Prior to this change the validation context used will simply be the
default behavior as if no `on` option were specified. With this change,
the validation_context of the parent record is passed to the `valid?`
check.

When associations are created or updated allow them to use their own
default context according to their own persistence status rather than
overriding with the context of their associated object.

Fixes #46239

Co-authored-by: Alex Ghiculescu <alex@tanda.co>
Co-authored-by: Rafał Brize <rafal@buyapowa.com>
2024-01-02 11:22:35 -05:00
Stephen Margheim 8ac2af29ad
Allow overriding SQLite defaults from `database.yml` (#50460)
* Allow overriding SQLite defaults from `database.yml`

Any PRAGMA configuration set under the `pragmas` key in the configuration file take precedence over Rails' defaults, and additional PRAGMAs can be set as well.

```yaml
database: storage/development.sqlite3
timeout: 5000
pragmas:
  synchronous: full
  temp_store: memory
```

* Style

* Allow overriding SQLite defaults from `database.yml`

Any PRAGMA configuration set under the `pragmas` key in the configuration file take precedence over Rails' defaults, and additional PRAGMAs can be set as well.

```yaml
database: storage/development.sqlite3
timeout: 5000
pragmas:
  synchronous: full
  temp_store: memory
```

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
2024-01-02 12:52:54 +01:00
Jean Boussier 6b446bee63 Remove SQLite production warning but leave production config disabled
There are valid use cases for running SQLite in production, however it must be done
with care, so instead of a warning most users won't see anyway, it's preferable to
leave the configuration commented out to force them to think about having the database
on a persistent volume etc.

Co-Authored-By: Jacopo Beschi <beschi.jacopo@gmail.com>
2023-12-27 23:32:18 +01:00
fatkodima f48bbff32c Expose `assert_queries_match` and `assert_no_queries_match` assertions 2023-12-21 01:30:16 +02:00
Stephen Margheim 4e7bdcf93a Add support for generated columns in SQLite3 adapter
Generated columns (both stored and dynamic) are supported since version 3.31.0 of SQLite.
This adds support for those to the SQLite3 adapter.

```ruby
create_table :users do |t|
  t.string :name
  t.virtual :name_upper, type: :string, as: 'UPPER(name)'
  t.virtual :name_lower, type: :string, as: 'LOWER(name)', stored: true
end
```
2023-12-14 18:19:02 +01:00
Jean Boussier 0fe087eb56 TrilogyAdapter: ignore host if socket is set
Contrary to mysql2, trilogy will ignore the `socket` config
if `host` is set.

This makes it impossible to configure a UNIX domain socket connection
via `DATABASE_URL`, as the URL must include a host.
2023-12-13 17:35:09 +01:00
Jean Boussier 3881518c47
Merge pull request #50281 from p8/activerecord/assert-queries
Expose `assert_queries` and `assert_no_queries` assertions
2023-12-12 00:29:45 +01:00
Petrik 8392c54e73 Expose `assert_queries` and `assert_no_queries` assertions
To assert the expected number of queries are made, Rails internally uses
`assert_queries` and `assert_no_queries`. These assertions can be
useful in applications as well.

By extracting these assertions to a module, the assertions can be
included where required.
These assertions are added to `ActiveSupport::TestCase` when
ActiveRecord is defined.

ActiveStorage, ActionView and ActionText are using this module now as
well, instead of duplicating the implementation.
The internal ActiveRecord::TestCase, used for testing ActiveRecord,
implements these assertions as well. However, these are slighlty more
advanced/complex and use the SQLCounter class. To keep things simple,
for now this implementation isn't used.
2023-12-11 12:31:16 +01:00
Aaron Patterson ab8f5c9d93
Merge pull request #50079 from tttffff/mysql_null_first_last_consistency
Arel nulls first/last implementation Mysql
2023-12-08 15:44:02 -08:00
abeidahmed c8caf6d867 [Fix #49874] `has_secure_token` calls the setter method on initialize
Follow-up to #49146

The original behavior of `has_secure_token` was to use the
`send("#{attribute}=", some_value)` method so that the setter method, if
defined, was called. PR #49146 replaced the `send` method with
`write_attribute` which doesn't call the setter method and breaks
existing applications.
2023-12-03 14:35:19 +04:00
Adrianna Chang 2854e378c8
Revert "Add config for validating migration timestamps" 2023-12-01 11:58:53 -05:00
Adrianna Chang 06575d1d75
Add `active_record.config.validate_migration_timestamps` option.
When set, validates that the timestamp prefix for a migration is in the form YYYYMMDDHHMMSS.
This is designed to prevent migration timestamps from being modified by hand.

It is turned off by default.
2023-11-30 16:04:06 -05:00
Kevin McPhillips 0ccf300add Add an `ActiveRecord.protocol_adapters` configuration which maps the protocol in a `DATABASE_URL` to a database adapter. 2023-11-28 20:23:58 -05:00
Kevin McPhillips db3d6924a8
Surface generic warning when MySQL returns a warning_count that is not 0 but 'SHOW WARNINGS' does not return any warnings. 2023-11-20 12:40:07 -05:00
tttffff 059caa2065 Arel/MySQL ordering `nulls_first` and `nulls_last`
Fixes #50079 where there is unexpected behaviour for MySQL

Previously:
 - Calling nulls_first on asc worked as expected
 - Calling nulls_first on desc ordered desc nulls last
 - Calling nuls_last on asc raised error
 - Calling nulls_last on desc raised error

Now:
 - Calling nulls_first on asc works as expected
 - Calling nulls_first on desc works as expected
 - Calling nulls_last on asc works as expected
 - Calling nulls_last on desc works as expected
2023-11-17 20:59:11 +00:00
Andrew Novoselac c7063f944a DatabaseConfigurations#configs_for can accept a symbol in the name parameter. 2023-11-14 17:25:19 -05:00
JohnAnon9771 fb5773b3e8 Fix HomogeneousIn for serialized attributes
Previously, `proc_for_binds` was introduced to address missing attribute
names when logging binds. However, this causes double serialization,
impacting searches involving serialized attributes. This commit fixes
the issue by replacing the type with `ActiveModel::Type.default_value`
so that the 2nd serialization is effectively a no-op.

Fixes #48072.
Fixes #48535.

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2023-11-09 15:26:13 -06:00
Andrew Novoselac e50182a42c Make the output of `ActiveRecord::Core#inspect` configurable.
By default, calling `inspect` on a record will yield a formatted string including just the `id`.

```ruby
Post.first.inspect #=> "#<Post id: 1>"
```

The attributes to be included in the output of `inspect` can be configured with
`ActiveRecord::Core#attributes_for_inspect`.

```ruby
Post.attributes_for_inspect = [:id, :title]
Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
```

With the `attributes_for_inspect` set to `:all`, `inspect` will list all the record's attributes.

```ruby
Post.attributes_for_inspect = :all
Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
```
2023-11-08 14:23:16 -05:00
MaicolBen 19869e765e Don't mark Float::INFINITY as changed when reassigning it
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2023-11-06 08:33:39 -06:00
fatkodima 81eeecda7e Support `RETURNING` clause for MariaDB
Co-authored-by: Nikolay Kondratyev <nkondratyev@yandex.ru>
2023-10-30 21:08:49 +02:00
Stephen Margheim ea17941e39 The SQLite3 adapter now implements the `supports_deferrable_constraints?` contract
Implementing the full `supports_deferrable_constraints?` contract allows foreign keys to be deferred by adding the `:deferrable` key to the `foreign_key` options in the `add_reference` and `add_foreign_key` methods.

```ruby
add_reference :person, :alias, foreign_key: { deferrable: :deferred }
add_reference :alias, :person, foreign_key: { deferrable: :deferred }
```
2023-10-28 12:38:01 +02:00