Commit Graph

2723 Commits

Author SHA1 Message Date
Matthew Nguyen 41c547cb47 Translate SQLite3::BusyException into ActiveRecord::StatementTimeout 2024-08-16 13:22:44 +02:00
Tony Novak 2ea8e89fd1 Update PostgreSQLAdapter#extensions to include schema name
This allows the schema dumper's generated `enable_extension` statements
to include the schema name, if different from `current_schema`.

[Fix #52312]
2024-08-14 12:26:50 -04:00
Vasiliy Ermolovich eaa74eedba
EncryptedAttributeType#type should return cast_type's type. (#52247) 2024-08-13 14:04:24 -07:00
Nixon 90b1108a64 Bulk insert fixtures on SQLite 2024-08-11 04:05:44 -03:00
Tony Novak eb6d1709fe Allow disable_extension to be called with schema-qualified name
Note that the PostgreSQL DROP EXTENSION statement does not accept a
schema name (see https://www.postgresql.org/docs/current/sql-dropextension.html).
Since we allow `enable_extension` to be called with a schema-qualified
name, this commit allows `disable_extension` to be similarly called with
a schema-qualified name, but the schema name is chopped off in the
generated SQL statement.
2024-08-06 11:48:44 -04:00
Tony Novak e800fc683d Make create_schema / drop_schema reversible in migrations 2024-08-02 14:37:23 +02:00
fatkodima fd52a754f2 Support batching using custom columns 2024-07-27 11:55:52 +03:00
John Hawthorn 3b6af165df Revert "Merge pull request #51987 from fatkodima/exists-and-loaded2"
This reverts commit c9075e3643, reversing
changes made to a14eb2dc84.
2024-07-26 13:23:55 -07:00
Stephen Margheim 1e2c9048c4 Use SQLite `IMMEDIATE` transactions when possible.
Transactions run against the SQLite3 adapter default to IMMEDIATE mode to
improve concurrency support and avoid busy exceptions.

Fixture transactions use DEFERRED mode transactions as all `joinable`
transactions become DEFERRED transactions.
2024-07-26 09:02:08 +02:00
Hana Harencarova 0bdf44d921 Raise specific exception when a connection is not defined
Co-authored-by: Matthew Draper <matthewd@github.com>
2024-07-16 19:53:46 +00:00
Xavier Noria 32c5a358bb Delete the deprecated constant ActiveRecord::ImmutableRelation 2024-07-13 12:51:40 +02:00
Joshua Young 154f4a4ba9 [Fix 48688] Duplicate callback execution when child autosaves parent with has_one and belongs_to 2024-07-07 11:03:45 +05:30
heka1024 75421601ce Introduce `compressor` option to `ActiveRecord::Encryption::Encryptor` 2024-07-03 18:48:07 +09:00
Hartley McGuire 5c8172554f
Add condensed #inspect for Pool, Adapter, Config
Previously, it was very easy to accidentally leak a database password in
production logs if an error ends up calling inspect on a ConnectionPool
or an individual connection (Adapter). This is due to the default
`#inspect` output for Pools and Adapters being unnecessarily large, and
both currently including passwords (through the DatabaseConfig of a
Pool, and the internal configuration of an Adapter).

This commit addresses these issues by defining a custom `#inspect` for
ConnectionPool, AbstractAdapter, and DatabaseConfig. The condensed
`#inspect` only includes a few valuable fields instead of all of the
internals, which prevents both the large output and passwords from being
included.
2024-06-21 21:23:04 +00:00
Nony Dutton 77cf5e6d92 Add `.shard_keys` & `.connected_to_all_shards`
Currently, there is no (simple) way to ask a model if it connects to a
single database or to multiple shards. Furthermore, without looping
through a model's connections, I don't believe there's an easy way to
return a list of shards a model can connect to.

This commit adds a `@shard_keys` ivar that's set whenever `.connects_to`
is called. It sets the ivar to the result of `shards.keys`. `shards` in
`.connects_to` defaults to an empty hash and therefore when calling
`connects_to database: {...}` `@shard_keys` will be set to an empty array.

`@shard_keys` is set _before_ the following lines:

```
if shards.empty?
  shards[:default] = database
end
```

This conditional sets the one and only shard (`:default`) to the value of `database`
that we pass to `.connects_to`. This allows for calling
`connected_to(shard: :default)` on models configured to only connect to
a database e.g.:

```ruby
class UnshardedBase < ActiveRecord::Base
  self.abstract_class = true

  connects_to database: { writing: :primary }
end

class UnshardedModel < UnshardedBase
end

UnshardedBase.connected_to(shard: :default) {
UnshardedBase.connection_pool.db_config.name } => primary
```

This is ultimately still an _unsharded_ model which is why `@shard_keys`
gets set before the conditional.

With the new `@shard_keys` ivar we need a way for descendants of the
abstract AR model to return that same value. For that we leverage the
existing `.connection_class_for_self` method. That method returns the
ancestor of the model where `.connects_to` was called, or returns self if
it's the connection class:

```ruby
class UnshardedBase < ActiveRecord::Base
  self.abstract_class = true

  connects_to database: { writing: :primary }
end

class UnshardedModel < UnshardedBase
end

ActiveRecord::Base.connection_class_for_self => ActiveRecord::Base

UnshardedBase.connection_class_for_self => UnshardedBase(abstract)

UnshardedModel.connection_class_for_self => UnshardedBase(abstract)
```

The new `.shard_keys` method is a getter which returns the value of
`@shard_keys` from the connection class or it returns an empty array.
The empty array is necessary in cases where `connects_to` was never
called.

Finally, I've added an `.connected_to_all_shards` method which takes all of the
arguments for `.connected_to` except for `shard`. Instead, it loops through
every shard key and then delegates everything else to `.connected_to`. I've
used `.map` instead of `.each` so that we can collect the results of each block.
2024-06-17 19:54:25 +02:00
fatkodima 9e85d04e2e Optimize `ActiveRecord::Relation#exists?` with no conditions for loaded relations 2024-06-14 13:49:11 +02:00
Igor Depolli 00f38563a4
[ActiveRecord] Add option `filter` on `in_order_of` (#51761)
* Add option  on

* Add CHANGELOG and fix method doc

* Rename option to 'filter' and fix grammar

* Adjust filter attribute

* Fix typo and solve conflict

* Update activerecord/test/cases/relation/field_ordered_values_test.rb

Co-authored-by: Timo Schilling <timo@schilling.io>

---------

Co-authored-by: Timo Schilling <timo@schilling.io>
Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
2024-06-12 15:14:06 -07:00
Jay Ang 3e371c6dd6 Fix issue with IDs reader on preloaded associations for composite primary keys 2024-06-04 22:13:05 +08:00
Garen J. Torikian 5ff9915db9
Allow one to set `strict_loading_mode` globally 2024-06-02 14:38:38 -05:00
Carlos Antonio da Silva e12ba4d539 Fix method reference in Active Record changelog [ci skip] 2024-05-29 13:52:16 -03:00
Theodor Tonum d28e7c29a2 Add `ActiveRecord::Relation#readonly?`
Indicates whether a relation was marked readonly.
2024-05-27 21:51:04 +02:00
Mike Dalessio 2bf7e25243
Raise a descriptive error when a store column is misconfigured
If a developer has neglected to use a structured column type (hstore
or json) or to declare a serializer with `ActiveRecord.store`:

```ruby
  class User < ActiveRecord::Base
    store_accessor :settings, :notifications
  end
```

then a `ConfigurationError` will now be raised with a descriptive
error message when the accessor is read or written:

```ruby
  puts user.notifications
  # ActiveRecord::ConfigurationError: the column 'settings' has not
  # been configured as a store.  Please make sure the column is
  # declared serializable via 'ActiveRecord.store' or, if your
  # database supports it, use a structured column type like hstore or
  # json.
```

Previously, in this situation, a `NoMethodError` was raised when the
accessor was read or written:

```ruby
  puts user.notifications
  # NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::Text
```

Raising a descriptive exception should help developers understand more
quickly what's wrong and how to fix it.

Closes #51699
2024-05-23 15:59:56 -04:00
Joshua Young 0516eafda2 [Fix #51720] Infer association klass as top level if model has same demodularized name 2024-05-23 08:04:57 +09:00
eileencodes 227c590d02
Add test and fix changelog for `schema_cache_ignored_table?` 2024-05-21 15:37:38 -04:00
eileencodes e815c6663a
Make public method for `schema_cache_ignored_tables?`
Previously we only provided a method to set the ignored schema cache
tables, but there was no way to ask if a table was ignored by the schema
cache. Applications may want to implement their own schema cache, or at
least run this check. Rather than forcing them to implement an internal
method, this adds a way to ask whether a table is ignored by the schema
cache code.

Usage:

```ruby
ActiveRecord.schema_cache_ignored_tables = ["developers"]
ActiveRecord.schema_cache_ignored_tables?("developers")
```
2024-05-21 14:42:25 -04:00
Rafael Mendonça França 52b417bca6
This will be released in 7.2, not 8 2024-05-14 18:05:40 +00:00
fatkodima 94af7c181a Change `BatchEnumerator#destroy_all` to return the total number of affected rows 2024-05-13 22:54:25 +03:00
Rafael Mendonça França bf59d363fb
Clean CHANGELOG for 8.0 2024-05-13 16:55:52 +00:00
Rafael Mendonça França 37fd0e7fe4
Development of Rails 8.0 starts now
🎉
2024-05-13 16:45:20 +00:00
fatkodima e057037c72 Support `touch_all` in batches 2024-05-13 09:23:57 +09:00
Sampat Badhe a44fbb11a3
Correct typo in activerecord changelog [ci skip]
Correct typo in activerecord changelog for -https://github.com/rails/rails/pull/50662
2024-05-12 10:43:00 +05:30
fatkodima 47f25b268a Add support for `:if_not_exists` and `:force` options to `create_schema` 2024-05-11 16:40:20 +03:00
lulalala 0a36c36dd8 Add index_errors: :nested_attributes_order mode
which respects reject_if and is in nested_attributes order.

When in default index_errors:true mode,
fix #24390 and return index based on full association order.
2024-05-09 20:03:53 +08:00
Nikita Vasilevsky 9cadf61835
Warn about changing `query_constraints:` behavior
This commit adds a deprecation warning for the `query_constraints:`
association option. This option will change behavior in the future versions
of Rails and applications are encouraged to switch to `foreign_key:` to preserve the
current behavior.
2024-05-08 20:08:09 +00:00
David Heinemeier Hansson e8e077dd16
Add ENV["SKIP_TEST_DATABASE_TRUNCATE"] flag to speed up multi-process test runs (#51686) 2024-05-06 17:04:01 -07:00
nisusam e0b7136b3e Fix typo from Changelog [ci skip] 2024-05-02 17:23:21 +05:30
Claire fc26e44181 Add support for recursive CTE in Active Record
```ruby
Post.with_recursive(
  post_and_replies: [
    Post.where(id: 42),
    Post.joins('JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id'),
  ]
)
```

Generates the following SQL:

```sql
WITH RECURSIVE "post_and_replies" AS (
  (SELECT "posts".* FROM "posts" WHERE "posts"."id" = 42)
  UNION ALL
  (SELECT "posts".* FROM "posts" JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id)
)
SELECT "posts".* FROM "posts"
```
2024-05-02 12:32:27 +02:00
Cody Cutrer 5c5e8d2fd6 Pass validate(_check)_constraint through change_table 2024-05-01 15:33:37 -06:00
Joé Dupuis 2c88c80fc7
Add a Date decoder to the pg adapter to type cast dates
at the connection level

Fix #51448

Type cast columns of type `date` to ruby `Date` when running a raw
query through `ActiveRecord::Base.connection.select_all`.
2024-04-29 19:16:18 -07:00
Reid Lynch 715276071f
Strict loading using `:n_plus_one_only` does not eagerly load child associations.
Before:

    ```ruby
    person = Person.find(1)
    person.strict_loading!(mode: :n_plus_one_only)
    person.posts.first
    # SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
    ```

    After:

    ```ruby
    person = Person.find(1)
    person.strict_loading!(mode: :n_plus_one_only)
    person.posts.first # this is 1+1, not N+1
    # SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
    ```

    Strict loading in `:n_plus_one_only` mode is designed to prevent performance issues when
    deeply traversing associations. It allows `Person.find(1).posts`, but _not_
    `Person.find(1).posts.map(&:category)`. With this change, child associations are no
    longer eagerly loaded, to match intended behavior and to prevent non-deterministic
    order issues caused by calling methods like `first` or `last`.
    Fixes #49473.
2024-04-19 00:05:13 +00:00
Rafael Mendonça França d60a23457c
Revert "Don't silently execute statements on migrations when they can't be reversed"
This reverts commit 5b04d448ab.

This is breaking more than it is fixing. We need to find a better way to
handle this.
2024-04-19 00:03:53 +00:00
Rafael Mendonça França 5b04d448ab
Don't silently execute statements on migrations when they can't be reversed
Fixes #51570.
2024-04-18 23:00:57 +00:00
Mike Dalessio fd1c635d2f Allow sqlite3 to float to version 2 2024-04-18 11:34:24 +02:00
fatkodima 82c02ef4d0 Allow `ActiveRecord::Base#pluck` to accept hash values 2024-04-13 21:39:36 +03:00
Petrik 79f0c6504d Fix small typo's in ActiveRecord Changelog [ci-skip] 2024-04-08 15:58:14 +02:00
Jean Boussier 3700aa90e3 Fix a typo in activerecord/CHANGELOG.md 2024-04-08 12:19:29 +02:00
Kevin McPhillips 869d802c48
Raise a descriptive error if the MySQL adapter fails to parse the version string. 2024-04-03 16:38:33 -04:00
Jean Boussier c2df237414 Allow to register transaction callbacks outside of a record
Ref: https://github.com/rails/rails/pull/26103
Ref: https://github.com/rails/rails/pull/51426

A fairly common mistake with Rails is to enqueue a job from inside a
transaction, and a record as argumemnt, which then lead to a RecordNotFound
error when picked up by the queue.

This is even one of the arguments advanced for job runners backed by the
database such as `solid_queue`, `delayed_job` or `good_job`. But relying
on this is undesirable iin my opinion as it makes the Active Job abstraction
leaky, and if in the future you need to migrate to another backend or even
just move the queue to a separate database, you may experience a lot of race
conditions of the sort.

But more generally, being able to defer work to after the current transaction
has been a missing feature of Active Record. Right now the only way to do it
is from a model callback, and this forces moving things in Active Record
models that sometimes are better done elsewhere. Even as a self-proclaimed
"service object skeptic", I often wanted this capability over the last decade,
and I'm sure it got asked or desired by many more people.

Also there's some 3rd party gems adding this capability using monkey patches.
It's not a reason to upstream the capability, but it's a proof that there is
demand for it.

Implementation wise, this proof of concept shows that it's not really hard to
implement, even with nested multi-db transactions support.

Co-Authored-By: Cristian Bica <cristian.bica@gmail.com>
2024-04-03 14:26:10 +02:00
fatkodima e79455f3d4 Add the ability to ignore counter cache columns while they are backfilling 2024-04-02 13:59:46 +03:00
Adrianna Chang eabcff22a8
Retry known idempotent SELECT queries on connection-related exceptions
This commit makes two types of queries retry-able by opting into our `allow_retry` flag:
1) SELECT queries we construct by walking the Arel tree via `#to_sql_and_binds`. We use a
new `retryable` attribute on collector classes, which defaults to true for most node types,
but will be set to false for non-idempotent node types (functions, SQL literals, etc). The
`retryable` value is returned from  `#to_sql_and_binds` and used by `#select_all` and
passed down the call stack, eventually reaching the adapter's `#internal_exec_query` method.

Internally-generated SQL literals are marked as retryable via a new `retryable` attribute on
`Arel::Nodes::SqlLiteral`.

2) `#find` and `#find_by` queries with known attributes. We set `allow_retry: true` in `#cached_find_by`,
and pass this down to `#find_by_sql` and `#_query_by_sql`.

These changes ensure that queries we know are safe to retry can be retried automatically.
2024-03-26 09:25:55 -04:00