Commit Graph

2714 Commits

Author SHA1 Message Date
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 5b04d448ab3e412aec7cfb372007cf8e5effaef8.

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
Carlos Antonio da Silva
61a3e61e77 Minor text / error message tweaks, fixes, and punctuation
Improve a few sentences and add punctuation to some recent changelog &
guide entries.

[ci skip]
2024-03-25 10:21:08 -03:00
Nikita Vasilevsky
3df4d6927d Add CHANGELOG entries for association composite primary and foreign keys 2024-03-25 08:38:56 -04:00
Jean Boussier
dd8fd52c07 Add config.active_record.permanent_connection_checkout setting
Controls whether `ActiveRecord::Base.connection` raises an error, emits a deprecation warning, or neither.

`ActiveRecord::Base.connection` checkouts a database connection from the pool and keep it leased until the end of
the request or job. This behavior can be undesirable in environments that use many more threads or fibers than there
is available connections.

This configuration can be used to track down and eliminate code that calls `ActiveRecord::Base.connection` and
migrate it to use `ActiveRecord::Base.with_connection` instead.

The default behavior remains unchanged, and there is currently no plans to change the default.
2024-03-21 12:19:15 +01:00
Carlos Antonio da Silva
f404a949ce Fix AR changelog reference to new config [ci skip] 2024-03-18 13:09:43 -03:00
Donal McBreen
5d528ba0c8
Add dirties option to uncached (#51204)
This adds a `dirties` option to `ActiveRecord::Base.uncached` and
`ActiveRecord::ConnectionAdapters::ConnectionPool#uncached`.

Setting `dirties` to `false`, means database writes to the connection
pool will not mark any query caches as dirty.

The option defaults to `true` which retains the existing behaviour and
clears query caches on all connection pools used by the current thread.

Co-authored-by: Jeremy Daer <jeremy@rubyonrails.org>
2024-03-02 19:01:24 -08:00
Jean Boussier
7263da542b Deprecate ConnectionPool#connection
Replaced by `#lease_connection` to better reflect what it does.

`ActiveRecord::Base#connection` is deprecated in the same way
but without a removal timeline nor a deprecation warning.

Inside the Active Record test suite, we do remove `Base.connection`
to ensure it's not used internally.

Some callsites have been converted to use `with_connection`,
some other have been more simply migrated to `lease_connection`
and will serve as a list of callsites to convert for
https://github.com/rails/rails/pull/50793
2024-03-01 14:32:55 +01:00
Jean Boussier
ef947f9932 Expose a generic fixture accessor for fixture names that may conflict with Minitest
```ruby
assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
```

This was brought to me by someone with a `Metadata` model. The fixtures
accessor being `metadata` which conflicts with the `metadata` method
recently added in `Minitest`.
2024-02-28 16:09:23 +01:00
Joshua Young
f42d9cbc32 [Fix #51164] Model.query_constraints with single non-primary-key column raises incorrect error 2024-02-28 14:19:10 +10:00
Rafael Mendonça França
939742d69e
Merge pull request #50901 from joshuay03/fix-autosave-has-one-setting-fk-when-unchanged
[Fix #50897] Autosaving `has_one` sets foreign key attribute when unchanged
2024-02-21 15:21:23 -05:00