Commit Graph

2702 Commits

Author SHA1 Message Date
Ryuta Kamizono 9084a9045f Add original author's credit for #49100 [ci-skip]
Since #41730 is the original work for the enum attribute validation.
2023-09-04 13:46:15 +09:00
Sean Doyle e85a3ec624
Change `has_secure_token` default to `on: :initialize`
Follow-up to [#47420][]

With the changes made in [#47420][], `has_secure_token` declarations can
be configured to execute in an `after_initialize` callback. This commit
proposed a new Rails 7.1 default: generate all `has_secure_token` values
when their corresponding models are initialized.

To preserve pre-7.1 behavior, applications can set
`config.active_record.generate_secure_token_on = :create`.

By default, generate the value when the model is initialized:

```ruby
class User < ApplicationRecord
  has_secure_token
end

record = User.new
record.token # => "fwZcXX6SkJBJRogzMdciS7wf"
```

With `config.active_record.generate_secure_token_on = :create`, generate
the value when the model is created:

```ruby
 # config/application.rb
config.active_record.generate_secure_token_on = :create

 # app/models/user.rb
class User < ApplicationRecord
  has_secure_token on: :create
end

record = User.new
record.token # => nil
record.save!
record.token # => "fwZcXX6SkJBJRogzMdciS7wf"
```

[#47420]: https://github.com/rails/rails/pull/47420

Co-authored-by: Hartley McGuire <skipkayhil@gmail.com>
2023-09-01 20:17:22 +00:00
Эдем 7c65a4b83b
Make enums validatable without raising error (#49100)
* Make enums validatable without raising error

* Trigger fail CI

Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
2023-09-01 15:31:12 -04:00
Rafael Mendonça França cdbc9b78cb
Merge pull request #49090 from skipkayhil/hm-change-column-precision-6
Fix change_column not setting precision for sqlite
2023-09-01 14:21:53 -04:00
Jean Boussier 9fd3d03dab
Merge pull request #49105 from Earlopain/ar-normalizes-where
Document `where` support for AR `normalizes`
2023-09-01 19:02:14 +02:00
Hartley McGuire 57a9e25f8e
Fix change_column not setting precision for sqlite
There were a few 6.1 migration compatibility fixes in [previous][1]
[commits][2]. Most importantly, those commits reorganized some of the
compatibility tests to ensure that the tests would run against every
Migration version. To continue the effort of improving test coverage for
Migration compatibility, this commit converts tests for create_table and
change_column setting the correct precision on datetime columns.

While the create_table tests all pass, the change_column test did not
pass for 7.0 versioned Migrations on sqlite. This was due to the sqlite
adapter not using new_column_definition to set the options on the new
column (new_column_definition is where precision: 6 gets set if no
precision is specified). This happens because columns can't be modified
in place in sqlite and instead the whole table must be recreated and the
data copied. Before this commit, change_column would use the options
of the existing column as a base and merge in the exact options (and
type) passed to change_column.

This commit changes the change_column method to replace the existing
column without using the existing options. This ensures that precision:
6 is set consistently across adapters when change_column is used to
create a datetime column.

[1]: c2f838e80c
[2]: 9b07b2d6ca
2023-09-01 16:57:19 +00:00
Earlopain 830957e213
Document `where` support for AR `normalizes`
Also some other small changelog tweak:
* Add normalize_value_for to the activerecord changelog
* Fix a wrong method reference in the 7.1 release notes
2023-09-01 18:13:23 +02:00
Nikita Vasilevsky 0df4df4d15
Add CHANGELOG entries for `ActiveModel::Conversion#to_key` changes
`8a5cf4cf4415ae1cdad7feecfb27149c151b0b10` made changes to `to_key` in order
to support composite identifiers. This commit adds CHANGELOG entries for those.
2023-09-01 15:41:05 +00:00
HParker 451053eca5 Add changelog entry for batching using loaded relations
This backfills a changelog entry for PR #48876. This is potentially something Rails users
should be aware of as in very specific situations it can be a change in behavior
2023-08-28 17:29:52 -07:00
Adrianna Chang ac83311bae
Deprecate `read_attribute(:id)` returning the primary key
This commit deprecates `read_attribute(:id)` returning the primary key
if the model's primary key is not the id column. Starting in Rails 7.2,
`read_attribute(:id)` will always return the value of the id column.

This commit also changes `read_attribute(:id)` for composite primary
key models to return the value of the id column, not the composite
primary key.
2023-08-23 16:36:32 -04:00
Hartley McGuire 9b07b2d6ca
Fix 6.1 change_table setting datetime precision
While working on #48969, I found that some of the Compatibility test
cases were not working correctly. The tests removed in this commit were
never running the `change_table` migration and so were not actually
testing that `change_table` works correctly. The issue is that the two
migrations created in these tests both have `nil` versions, and so the
Migrator only runs the first one.

This commit refactors the tests so that its easier to test the behavior
of each Migration class version (and I think the rest of the tests
should be updated to use this strategy as well). Additionally, since the
tests are fixed it exposed that `t.change` in a `change_table` is not
behaving as expected so that is fixed as well.
2023-08-22 14:01:52 -04:00
Hartley McGuire c2f838e80c
Fix 6.1 change_column setting datetime precision
This is already the case for add_column and create_table, but
change_column was missed
2023-08-21 19:10:14 -04:00
Rafael Mendonça França ccee593fed
Merge pull request #48930 from adrianna-chang-shopify/ac-id-value
Use `alias_attribute` to provide `id_value` alias for `id` attribute
2023-08-21 14:33:39 -04:00
Adrianna Chang e90b11e77e
Use alias_attribute to provide #id_value alias for #id
This allows access to the raw id column value on records for which an
id column exists but is not the primary key. This is common amongst
models with composite primary keys.
2023-08-21 14:12:53 -04:00
Takumi Shotoku 0e41e2cd8e
Fix method name to `check_all_pending!`
The method added in 03379d1f59 is `check_all_pending!`, not
`check_pending_migrations!`.
2023-08-17 16:51:39 +09:00
Robert DiMartino eceaa38e06
Fix tracking previous changes for ActiveRecord::Store accessors with underlying JSON data column 2023-08-07 22:26:45 -04:00
Rafael Mendonça França fbaba19e2d
Merge PR #48608 2023-08-03 19:29:30 +00:00
Justin Bull 694376f15e Allow use of backslashes to escape literal colons
Despite the inconvenience of double-backslashing, the backslash was chosen
because it's a very common char to use in escaping across multiple programming
languages. A developer, without looking at documentation, may intuitively try
to use it to achieve the desired results in this scenario.

Fixes #37779
2023-07-30 07:55:02 -04:00
Adrianna Chang 7981988fa0
Fix #previously_new_record? on destroyed records
Ref: #48794

`#previously_new_record?` should return false for records that are
created and then destroyed.
2023-07-25 15:49:49 -04:00
Gregory Jones 4837bcaeef
Merge branch 'main' into postgres-index-nulls-not-distinct 2023-07-18 15:05:24 -04:00
Sean Doyle 7d63864486 Specify when to generate `has_secure_token`
The callback when the value is generated. When called with `on:
:initialize`, the value is generated in an `after_initialize` callback,
otherwise the value will be used in a `before_` callback. It will
default to `:create`.
2023-07-18 14:48:30 -04:00
Jacopo 186474f273 Fix counter_cache create/concat with overlapping counter_cache_column
Fix when multiple `belongs_to` maps to the same counter_cache column.
In such situation `inverse_which_updates_counter_cache` may find the
wrong relation which leads into an invalid increment of the
counter_cache.

This is done by releying on the `inverse_of` property of the relation
as well as comparing the models the association points two.

Note however that this second check doesn't work for polymorphic
associations.

Fixes #41250

Co-Authored-By: Jean Boussier <jean.boussier@gmail.com>
2023-07-13 12:06:08 +02:00
Petrik de Heus f768944bdf
Merge branch 'main' into activerecord/aes256gm-inspect 2023-07-11 21:10:42 +02:00
Jean Boussier 5fbaa524b9 Active Record commit transaction on `return`, `break` and `throw`
Fix: https://github.com/rails/rails/issues/45017
Ref: https://github.com/rails/rails/pull/29333
Ref: https://github.com/ruby/timeout/pull/30

Historically only raised errors would trigger a rollback, but in Ruby `2.3`, the `timeout` library
started using `throw` to interupt execution which had the adverse effect of committing open transactions.

To solve this, in Active Record 6.1 the behavior was changed to instead rollback the transaction as it was safer
than to potentially commit an incomplete transaction.

Using `return`, `break` or `throw` inside a `transaction` block was essentially deprecated from Rails 6.1 onwards.

However with the release of `timeout 0.4.0`, `Timeout.timeout` now raises an error again, and Active Record is able
to return to its original, less surprising, behavior.
2023-07-10 10:37:42 +02:00
eileencodes b69fa80b66
Deprecate `name` argument in `remove_connection`
The `name` argument is not useful as `remove_connection` should be called
on the class that established the connection. Allowing `name` to be
passed here doesn't match how any of the other methods behave on the
connection classes. While this behavior has been around for a long time,
I'm not sure anyone is using this as it's not documented when to use
name, nor are there any tests.
2023-07-06 15:55:35 -04:00
Petrik 7dd38cfa16 Don't show secrets for Active Record's `Cipher::Aes256Gcm#inspect`.
If anyone calls a cypher in the console it will show the secret of the
encryptor.

By overriding the `inspect` method to only show the class name we can
avoid accidentally outputting sensitive information.

Before:

```ruby
ActiveRecord::Encryption::Cipher::Aes256Gcm.new(secret).inspect
"#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038 ... @secret=\"\\xAF\\bFh]LV}q\\nl\\xB2U\\xB3 ... >"
```

After:

```ruby
ActiveRecord::Encryption::Cipher::Aes256Gcm(secret).inspect
"#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038>"
```
2023-07-06 21:41:27 +02:00
Gannon McGibbon 68e0dd2c83 Fix has_one through singular building with inverse.
Allows building of records from an association with a has_one through a
singular association with inverse. For belongs_to through associations,
linking the foreign key to the primary key model isn't needed.
For has_one, we cannot build records due to the association not being mutable.
2023-07-05 23:22:51 -05:00
zzak a234669d63
Disable database prepared statements when query logs are enabled
Fixes #48398

Prepared Statements and Query Logs are incompatible features due to query logs making every query unique.

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2023-07-03 16:59:44 +09:00
Rafael Mendonça França e366af5bf5
Revert "Merge pull request #48487 from lazaronixon/scope-subqueries"
This reverts commit 6264c1de76, reversing
changes made to 6c80bcdd20.

Reason: Still discussion about the feature. We want to make it opt-in
but we need to better understand why people would want to opt-in to
this behavior.
2023-06-29 15:25:53 +00:00
Gregory Jones 698369d642 Linting fixes 2023-06-28 23:41:20 -04:00
Gregory Jones 10bad051a8 Support NULLS NOT DISTINCT in Postgres 15+ 2023-06-28 23:24:57 -04:00
Jorge Manrubia c8d26bb647
Add a encryption option to support previous data encrypted non-deterministically with a SHA1 hash digest (#48530)
* Make sure active record encryption configuration happens after initializers have run

Co-authored-by: Cadu Ribeiro <mail@cadu.dev>

* Add a new option to support previous data encrypted non-deterministically with a hash digest of SHA1

There is currently a problem with Active Record encryption for users updating from 7.0 to 7.1 Before
#44873, data encrypted with non-deterministic encryption was always using SHA-1. The reason is that
`ActiveSupport::KeyGenerator.hash_digest_class` is set in an after_initialize block in the railtie config,
but encryption config was running before that, so it was effectively using the previous default SHA1. That
means that existing users are using SHA256 for non deterministic encryption, and SHA1 for deterministic
encryption.

This adds a new option `use_sha1_digest_for_non_deterministic_data` that
users can enable to support for SHA1 and SHA256 when decrypting existing data.

* Set a default value of true for `support_sha1_for_non_deterministic_encryption` and proper initializer values.

We want to enable the flag existing versions (< 7.1), and we want it to be false moving by
default moving forward.

* Make sure the system to auto-filter params supports different initialization orders

This reworks the system to auto-filter params so that it works when encrypted
attributes are declared before the encryption configuration logic runs.

Co-authored-by: Cadu Ribeiro <mail@cadu.dev>

---------

Co-authored-by: Cadu Ribeiro <mail@cadu.dev>
2023-06-25 10:16:22 +02:00
Guillermo Iguaran d9f22a40e2 Revert "Fix a typo in CHANGELOG.md"
This reverts commit e446ef82c8.

Array#intersect? is the correct name: https://rubyapi.org/3.2/o/array#method-i-intersect-3F
2023-06-21 13:07:08 -07:00
Jean Boussier e446ef82c8
Fix a typo in CHANGELOG.md
Ref: https://github.com/rails/rails/pull/47670/files#r1236168967

It's `intersects?` not `intersect?`
2023-06-21 09:11:42 +02:00
Nixon 8d520e0359 Apply scope to association subqueries 2023-06-16 15:48:24 -03:00
Ray Faddis ce6047f84f Adding PG enum rename, add value, and rename value migration helpers 2023-06-15 10:03:23 -04:00
ippachi ed680483db
Fix unscope not working when where by tripe dot range
Fix #48094
2023-06-14 01:15:08 +09:00
Nikita Vasilevsky 257f0124fc
Allow composite primary key to be derived from schema
This commit stops issuing the
"Active Record does not support composite primary key" warning
and allows `ActiveRecord::Base#primary_key` to be derived as an `Array`
2023-06-06 14:39:04 +00:00
Matthew Draper 3e01b26a16 Merge pull request #48295 from luanzeba/connection_attr_reader
Store `connection_pool` in database-related exceptions
2023-06-06 20:33:55 +09:30
takuyaK 9452b59506 Support batching using composite primary keys and multiple column ordering
When find_each/find_in_batches/in_batches are performed on a table with composite primary keys, ascending or descending order can be selected for each key.

    ```ruby
    Person.find_each(order: [:desc, :asc]) do |person|
      person.party_all_night!
    end
    ```
2023-06-05 21:59:38 +09:00
Rafael Mendonça França 80271fe5a4
Cleanup CHANGELOG of feature that will not be released 2023-06-02 21:07:24 +00:00
Luan Vieira 7d4c88dde3
Store connection_pool in DB exceptions
Anytime an exception is raised from an adapter we now provide a
`connection_pool` along for the application to further debug what went
wrong. This is an important feature when running a multi-database Rails
application.

We chose to provide the `connection_pool` as it has relevant context
like connection, role and shard. We wanted to avoid providing the
`connection` directly as it might accidentally be used after it's
returned to the pool and been handed to another thread.
The `ConnectionAdapters::PoolConfig` would also have been a reasonable
option except it's `:nodoc:`.
2023-06-02 10:44:28 -04:00
Nixon aa41938e3a Fix polymorphic association subquery 2023-06-02 02:50:23 -03:00
eileencodes a6efde6cf6
Minor changelog edits 2023-06-01 16:13:33 -04:00
eileencodes 2c39149e99
Revert deprecation message for prepared statements
While we had hoped to turn prepared statements on for Rails 7.2, the bug
that's preventing us from doing that is still present. See #43005.

Until this bug is fixed we should not be encouraging applications
running mysql to change the `prepared_statements` in the config to
`true`. In addition to this bug being present, Trilogy does not yet
support `prepared_statements` (although work is in progress).

It will be better to implement this deprecation when mysql2 and trilogy
can both handle `prepared_statements` without major bugs.
2023-06-01 16:11:55 -04:00
Nikita Vasilevsky c92933265e
Assign auto populated columns on Active Record object creation
This commit extends Active Record creation logic to allow for a database
auto-populated attributes to be assigned on object creation.

Given a `Post` model represented by the following schema:
```ruby
create_table :posts, id: false do |t|
  t.integer :sequential_number, auto_increment: true
  t.string :title, primary_key: true
  t.string :ruby_on_rails, default: -> { "concat('R', 'o', 'R')" }
end
```
where `title` is being used as a primary key, the table has an
integer `sequential_number` column populated by a sequence and
`ruby_on_rails` column has a default function - creation of
`Post` records should populate the `sequential_number` and
`ruby_on_rails` attributes:

```ruby
new_post = Post.create(title: 'My first post')
new_post.sequential_number # => 1
new_post.ruby_on_rails # => 'RoR'
```

* At this moment MySQL and SQLite adapters are limited to only one
column being populated and the column must be the `auto_increment`
while PostgreSQL adapter supports any number of auto-populated
columns through `RETURNING` statement.
2023-06-01 14:39:12 +00:00
eileencodes 0d41bfd3cc
Set default_shard from connects_to hash
If an application is using sharding, they may not want to use `default`
as the `default_shard`. Unfortunately Rails expects there to be a shard
named `default` for certain actions internally. This leads to some
errors on boot and the application is left manually setting
`default_shard=` in their model or updating their shards in
`connects_to` to name `shard_one` to `default`. Neither are a great
solution, especially if Rails can do this for you. Changes to Active
Record are:

* Simplify `connects_to` by merging `database` into `shards` kwarg so we
can do a single loop through provided options.
* Set the `self.default_shard` to the first keys in the shards kwarg.
* Add a test for this behavior
* Update existing test that wasn't testing this to use `default`. I
could have left this test but it really messes with connections in the
other tests and since this isn't testing shard behavior specifically, I
updated it to use `default` as the default shard name.

This is a slight change in behavior from existing applications but
arguably this is fixing a bug because without this an application won't
boot. I originally thought that this would require a huge refactoring to
fix but realized that it makes a lot of sense to take the first shard as
they default. They should all have the same schema so we can assume it's
fine to take the first one.

Fixes: #45390
2023-05-31 12:52:12 -04:00
Jon Zeppieri 6debbcae78 Remove changelog entry for Arel feature
As @rafaelfranca points out, Arel is private, so changes to it
don't go in the changelog.
2023-05-25 09:27:34 -04:00
Aaron Patterson 2dbc7dbac8
Merge pull request #48261 from 97jaz/arel-cte-node
Adds Arel::Nodes::Cte for use in WITH expressions
2023-05-24 16:53:29 -07:00
Jon Zeppieri 355b65ddb4 Adds Arel::Nodes::Cte for use in WITH expressions
SelectManager#with currently accepts As and TableAlias nodes.
Neither of these support materialization hints for the query
planner. Both Postgres and SQLite support such hints.

This commit adds a Cte node that does support materialization
hints. It continues to support As and TableAlias nodes by
translating them into Cte nodes.
2023-05-24 19:19:21 -04:00
Rafael Mendonça França b070c4d610
Simplify the implementation to register the correct source_path for the migration template 2023-05-24 22:54:12 +00:00
Spencer Neste a8fe415f85
Model Generator Source Paths Should Allow for Customization
Co-authored-by: Joshua Flanagan <joshuaflanagan@gmail.com>
2023-05-24 22:13:45 +00:00
Jean Boussier 108617eb74 Fix change_in_place? for binary serialized columns
Followup: https://github.com/rails/rails/pull/40383
Fix: https://github.com/rails/rails/issues/48255
Fix: https://github.com/rails/rails/pull/48262

If the serialized attribute is backed by a binary column, we must ensure
that both the `raw_old_value` and the `raw_new_value` are casted to
`Binary::Data`.

Additionally, `Binary::Data` must cast it's backing string in
`Encoding::BINARY` otherwise comparison of strings containing bytes
outside the ASCII range will fail.
2023-05-22 13:01:42 +02:00
Jean Boussier f1b15971a5 Implement `ActiveRecord.disconnect_all!` to close all connections
This is basically a multi-db aware version of `ActiveRecord::Base.connection.disconnect!`.
It also avoid connecting to the database if we weren't already.

This can be useful to reset state after `establish_connection` has been used.
2023-05-19 13:19:31 +02:00
eileencodes 942785fb8b
Revert "Merge pull request #48188 from eileencodes/revert-48069"
This reverts commit 6adaeb8649, reversing
changes made to a792a62080.

We're going to forward fix this in our application rather than keep this
revert in. Reverting other changes has turned out to be too difficult to
get back to a state where our application is retrying queries.
2023-05-15 10:38:36 -04:00
Nick Dower bdd0015873 Discard connections which may be left in a transaction
Partially Fixes #48164

Today, connections are discarded in `within_transaction` if rolling back
fails after the call to `yield` raises. This is done to prevent a
connection from being left in a transaction if the rollback actually
failed.

This change causes connections to be discarded in the following
additional cases where the connection may be left in a transaction:
- If beginning the transaction fails.
- If rolling back the transaction fails.
- If committing the transaction fails, then rolling back fails.

This is accomplished by rescuing all exceptions raised in
`within_transaction` and discarding the connection if the transaction
has not been been both initialized and completed.
2023-05-13 11:41:05 +02:00
Olivier e394c38f3e
Update ActiveRecord CHANGELOG.md 2023-05-11 10:54:13 -04:00
eileencodes 338e1f785a
Revert "Merge pull request #48069 from Shopify/ar-exec-query-flush-cache"
This reverts commit 663df3aa09, reversing
changes made to 9b4fff264e.

The changes here forced our code through a different codepath,
circumventing the patch on `execute` to retry queries. Since we also
patch `execute` from Semian it's not clear the correct path forward and
we're going to revert for now.
2023-05-10 14:17:48 -04:00
sampatbadhe 85dc814fd6 Update changelog for https://github.com/rails/rails/pull/48110 2023-05-07 08:54:30 +05:30
Jean Boussier 89a5d6ada5 Make Active Record's query cache an LRU
I don't know how prevalent this really is, but I heard several time
about users having memory exhaustion issues caused by the query cache
when dealing with long running jobs.

Overall it seems sensible for this cache not to be entirely unbounded.
2023-05-07 11:16:56 +09:00
eileencodes 03379d1f59
Deprecate `check_pending!` in favor of `check_all_pending!`
`check_pending!` takes a connection that defaults to `Base.connection`
(or migration_connection but right now that's always Base.connection).
This means that we aren't able to loop through all the configs for an
environment because this is a public API that accepts a single
connection. To fix this I've deprecated `check_pending!` in favor of
`check_all_pending!` which will loop through the configs and check for
pending migrations on all the connections.

Example results:

```
Migrations are pending. To resolve this issue, run:

        bin/rails db:migrate

You have 3 pending migrations:

db/migrate/20221213152217_create_posts.rb
db/migrate/20230503150812_add_active_column_to_posts.rb
db/secondary_migrate/20230503173111_create_dogs.rb
```

Before this change, only migrations in `db/migrate` or
`db/secondary_migrate` would be output by `ActiveRecord::Migration.check_pending!`.
I chose not to accept a connection or db_config argument for this new
method because it's not super useful. It's more useful to know all
pending migrations. If it becomes problematic, we can reimplement the
connection option on this method (or reintroduce `check_pending!`.
2023-05-05 13:55:58 -04:00
fatkodima cabc1842b7 Make `increment_counter`/`decrement_counter` accept an amount argument 2023-05-05 12:18:31 +03:00
Jean Boussier b717a5a0d4 Revert "Merge pull request #47352 from basecamp/ar-freeze-cached"
This reverts commit 2c20f90eba, reversing
changes made to 912096d4ce.
2023-05-02 10:53:14 +02:00
Jorge Manrubia f195e033ac Freeze casted values instead of original values in database queries
This deals with a problem introduced in #7743ab95b8e15581f432206245c691434a3993d1a751b9d451170956d59457a9R8
that was preventing query `Class` serialized attributes. Duplicating the original
`Class` argument generates an anonymous class that can't be serialized as YAML.

This change makes query attributes hasheable based on their frozen casted values
to prevent the problem.

This solution is based on an idea by @matthewd from https://github.com/rails/rails/issues/47338#issuecomment-1424402777.
2023-05-02 10:09:20 +02:00
John Kelly c837ae624b Add `intersects?` to Relation
Ruby 3.1 added `intersects?` which is equivalent to `(a & b).any?`. Rubocop added a corresponding cop, `Style/ArrayIntersect`, which transforms the old style to use `intersect?`. Unfortunately as `intersects?` is not delegated on `CollectionProxy`, this leads to false positives that need to be disabled for no good reason other than the fact the method isn't delegated.

This PR add delegation of `intersects?` to `Relation` which fixes this.
2023-04-27 16:09:34 +02:00
alpaca-tc ec0a2a9d98 The deferrable foreign key can be passed to `t.references`.
Fixed a bug in which deferrable foreign_key was ignored when passed to `t.references`.
2023-04-27 10:43:58 +09:00
alpaca-tc 896d35910a Deprecate `deferrable: true` option of `add_foreign_key`.
`deferrable: true` is deprecated in favor of `deferrable: :immediate`, and
will be removed in Rails 7.2.

Because `deferrable: true` and `deferrable: :deferred` are hard to understand.
Both true and :deferred are truthy values.
This behavior is the same as the deferrable option of the add_unique_key method, added in #46192.

*Hiroyuki Ishii*
2023-04-26 21:48:17 +09:00
Jean Boussier 3a32921a0a Make Adapter#exec_query clear the query cache
It's public API and we can't assume whether the query is read only
so we should clear the cache.

To perform read only queries, `select` and `select_all` can be used.
2023-04-26 12:59:51 +02:00
Rafael Mendonça França fb4881270b
Merge PR #46843 2023-04-25 18:27:08 +00:00
fatkodima 00b8ce6fe5 Add load hook for `ActiveRecord::ConnectionAdapters::Mysql2Adapter` 2023-04-21 22:00:39 +03:00
alpaca-tc f5c1222660 Adds support `USING INDEX` for unique constraints in PostgreSQL.
Adds `:using_index` option to use an existing index when defining a unique constraint.
If you want to change an existing unique index to deferrable, you can use :using_index to create deferrable unique constraints.

```ruby
add_unique_key :users, deferrable: :immediate, using_index: 'unique_index_name'
```

A unique constraint internally constructs a unique index.
If an existing unique index has already been created, the unique constraint
can be created much faster, since there is no need to create the unique index
when generating the constraint.
2023-04-19 13:48:09 +09:00
Vladimir Dementyev 92bb466dde
Support using CTE names in left_outer_joins 2023-04-18 12:24:50 -04:00
Adrianna Chang 5ed3f60df6
Introduce adapter for Trilogy, a MySQL-compatible DB client
The [Trilogy database client][trilogy-client] and corresponding
[Active Record adapter][ar-adapter] were both open sourced by GitHub last year.

Shopify has recently taken the plunge and successfully adopted Trilogy in their Rails monolith.
With two major Rails applications running Trilogy successfully, we'd like to propose upstreaming the adapter
to Rails as a MySQL-compatible alternative to Mysql2Adapter.

[trilogy-client]: https://github.com/github/trilogy
[ar-adapter]: https://github.com/github/activerecord-trilogy-adapter

Co-authored-by: Aaron Patterson <tenderlove@github.com>
Co-authored-by: Adam Roben <adam@roben.org>
Co-authored-by: Ali Ibrahim <aibrahim2k2@gmail.com>
Co-authored-by: Aman Gupta <aman@tmm1.net>
Co-authored-by: Arthur Nogueira Neves <github@arthurnn.com>
Co-authored-by: Arthur Schreiber <arthurschreiber@github.com>
Co-authored-by: Ashe Connor <kivikakk@github.com>
Co-authored-by: Brandon Keepers <brandon@opensoul.org>
Co-authored-by: Brian Lopez <seniorlopez@gmail.com>
Co-authored-by: Brooke Kuhlmann <brooke@testdouble.com>
Co-authored-by: Bryana Knight <bryanaknight@github.com>
Co-authored-by: Carl Brasic <brasic@github.com>
Co-authored-by: Chris Bloom <chrisbloom7@github.com>
Co-authored-by: Cliff Pruitt <cliff.pruitt@cliffpruitt.com>
Co-authored-by: Daniel Colson <composerinteralia@github.com>
Co-authored-by: David Calavera <david.calavera@gmail.com>
Co-authored-by: David Celis <davidcelis@github.com>
Co-authored-by: David Ratajczak <david@mockra.com>
Co-authored-by: Dirkjan Bussink <d.bussink@gmail.com>
Co-authored-by: Eileen Uchitelle <eileencodes@gmail.com>
Co-authored-by: Enrique Gonzalez <enriikke@gmail.com>
Co-authored-by: Garrett Bjerkhoel <garrett@github.com>
Co-authored-by: Georgi Knox <georgicodes@github.com>
Co-authored-by: HParker <HParker@github.com>
Co-authored-by: Hailey Somerville <hailey@hailey.lol>
Co-authored-by: James Dennes <jdennes@gmail.com>
Co-authored-by: Jane Sternbach <janester@github.com>
Co-authored-by: Jess Bees <toomanybees@github.com>
Co-authored-by: Jesse Toth <jesse.toth@github.com>
Co-authored-by: Joel Hawksley <joelhawksley@github.com>
Co-authored-by: John Barnette <jbarnette@github.com>
Co-authored-by: John Crepezzi <john.crepezzi@gmail.com>
Co-authored-by: John Hawthorn <john@hawthorn.email>
Co-authored-by: John Nunemaker <nunemaker@gmail.com>
Co-authored-by: Jonathan Hoyt <hoyt@github.com>
Co-authored-by: Katrina Owen <kytrinyx@github.com>
Co-authored-by: Keeran Raj Hawoldar <keeran@gmail.com>
Co-authored-by: Kevin Solorio <soloriok@gmail.com>
Co-authored-by: Leo Correa <lcorr005@gmail.com>
Co-authored-by: Lizz Hale <lizzhale@github.com>
Co-authored-by: Lorin Thwaits <lorint@gmail.com>
Co-authored-by: Matt Jones <al2o3cr@gmail.com>
Co-authored-by: Matthew Draper <matthewd@github.com>
Co-authored-by: Max Veytsman <mveytsman@github.com>
Co-authored-by: Nathan Witmer <nathan@zerowidth.com>
Co-authored-by: Nick Holden <nick.r.holden@gmail.com>
Co-authored-by: Paarth Madan <paarth.madan@shopify.com>
Co-authored-by: Patrick Reynolds <patrick.reynolds@github.com>
Co-authored-by: Rob Sanheim <rsanheim@gmail.com>
Co-authored-by: Rocio Delgado <rocio@github.com>
Co-authored-by: Sam Lambert <sam.lambert@github.com>
Co-authored-by: Shay Frendt <shay@github.com>
Co-authored-by: Shlomi Noach <shlomi-noach@github.com>
Co-authored-by: Sophie Haskins <sophaskins@github.com>
Co-authored-by: Thomas Maurer <tma@github.com>
Co-authored-by: Tim Pease <tim.pease@gmail.com>
Co-authored-by: Yossef Mendelssohn <ymendel@pobox.com>
Co-authored-by: Zack Koppert <zkoppert@github.com>
Co-authored-by: Zhongying Qiao <cryptoque@users.noreply.github.com>
2023-04-17 11:49:07 -04:00
Alex Ghiculescu 3bcd167c3e Run `after_commit` callbacks defined on models in the correct order 2023-04-05 14:21:33 -06:00
Viktor Habchak 0bbaee32bb Fix ActiveRecord CHANGELOG typo. 2023-03-31 17:30:49 +02:00
Daniel Whitney 15369fd912
Infer `foerign_key` when `inverse_of` is present (#47797)
* Infer `foerign_key` when `inverse_of` is present

Automatically infer `foreign_key` on `has_one` and `has_many` associations when `inverse_of` is present.

When inverse of is present, rails has all the info it needs to figure out what the foreign_key on the associated model should be.  I can't imagine this breaking anything

* Update test models to remove redundant foreign_keys

* add changelog entry

* fix changelog grammar

Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
2023-03-30 15:22:23 -04:00
Jean Boussier 59f2b06493 Use idx_ instead of ix_ for index prefix
Followup: #47753
2023-03-29 09:28:46 +02:00
Mike Coutermarsh 3682aa1016
Fix Rails generated index name being too long
This updates the index name generation to always create a valid index name if one is not passed by the user.

Set the limit to 62 bytes to ensure it works for the default configurations of Sqlite, mysql & postgres.

MySQL: 64
Postgres: 63
Sqlite: 62

When over the limit, we fallback to a "short format" that includes a hash to guarantee uniqueness in the generated index name.
2023-03-28 17:34:52 -04:00
Jean Boussier dee93277e3 Implement `marshal_dump` and `marshal_load` on ActiveRecord::Base
Fix: https://github.com/rails/rails/issues/47704
Superseed: https://github.com/rails/rails/pull/47722

While the instance variable ordering bug will be fixed in Ruby 3.2.2,
it's not great that we're depending on such brittle implementation detail.

Additionally, Marshalling Active Record instances is currently very inefficient,
the payload include lots of redundant data that shouldn't make it into the cache.

In this new format the serialized payload only contains basic Ruby core or stdlib objects,
reducing the risk of changes in the internal representation of Rails classes.
2023-03-28 16:46:14 +02:00
Paarth Madan e39e013cf7 Specify where clauses by mapping columns to tuples
With the introduction of composite primary keys, a common usecase is querying for records with tuples representing the composite key. This change introduces new syntax to the where clause that allows specifying an array of columns mapped to a list of corresponding tuples. It converts this to an OR-joined list of separate queries, similar to previous implementations that rely on grouping queries.
2023-03-22 13:56:47 -04:00
Nick Borromeo 6bd100711c Allow SQL Warnings to be ignored using error codes
In https://github.com/rails/rails/pull/46690 the `db_warnings_action` and `db_warnings_ignore` configs where added. The
`db_warnings_ignore` can take a list of warning messages to match against.

At GitHub we have a subscriber that that does something like this but also filters out error codes. There might also be
other applications that filter via error codes and this could be something they can use instead of just the explicit
messages.

This also refactors the adapter tests in order for mysql2 and postgresql adapters to share the same helper when setting
the db_warnings_action and db_warnings_ignore configs
2023-03-20 13:06:22 -07:00
sampatbadhe d9d8d8a4d2 Correct typos in activerecord changelog and querylogs docs [ci-skip] 2023-03-18 19:07:41 +05:30
Andrew Novoselac 49283adc16 Run a load hook when TestFixtures is included 2023-03-17 13:36:48 -04:00
Rafael Mendonça França 74554cde8b
Merge PR #47675 2023-03-15 13:05:44 +00:00
Andrew Novoselac 6902cbce1b Introducs `TestFixtures#fixture_paths`.
Multiple fixture paths can now be specified using the `#fixture_paths` accessor.
2023-03-14 19:02:56 -04:00
alpaca-tc cbc7b59749 Adds support for deferrable exclude constraints in PostgreSQL.
By default, exclude constraints in PostgreSQL are checked after each statement.
This works for most use cases, but becomes a major limitation when replacing
records with overlapping ranges by using multiple statements.

```ruby
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :immediate
```

Passing `deferrable: :immediate` checks constraint after each statement,
but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED`
within a transaction. This will cause the excludes to be checked after the transaction.

It's also possible to change the default behavior from an immediate check
(after the statement), to a deferred check (after the transaction):

```ruby
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :deferred
```

*Hiroyuki Ishii*
2023-03-14 23:29:35 +09:00
Jason Karns 1f61fd65ae
Delegated Type supports customizeable foreign_type column 2023-03-14 09:19:30 -04:00
alpaca-tc d849ee04c6 Add support for unique constraints (PostgreSQL-only).
```ruby
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_key :sections, name: "unique_section_position"
```

See PostgreSQL's [Unique Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS) documentation for more on unique constraints.

By default, unique constraints in PostgreSQL are checked after each statement.
This works for most use cases, but becomes a major limitation when replacing
records with unique column by using multiple statements.

An example of swapping unique columns between records.

```ruby
old_item = Item.create!(position: 1)
new_item = Item.create!(position: 2)

Item.transaction do
  old_item.update!(position: 2)
  new_item.update!(position: 1)
end
```

Using the default behavior, the transaction would fail when executing the
first `UPDATE` statement.

By passing the `:deferrable` option to the `add_unique_key` statement in
migrations, it's possible to defer this check.

```ruby
add_unique_key :items, [:position], deferrable: :immediate
```

Passing `deferrable: :immediate` does not change the behaviour of the previous example,
but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED` within a transaction.
This will cause the unique constraints to be checked after the transaction.

It's also possible to adjust the default behavior from an immediate
check (after the statement), to a deferred check (after the transaction):

```ruby
add_unique_key :items, [:position], deferrable: :deferred
```

PostgreSQL allows users to create a unique constraints on top of the unique
index that cannot be deferred. In this case, even if users creates deferrable
unique constraint, the existing unique index does not allow users to violate uniqueness
within the transaction. If you want to change existing unique index to deferrable,
you need execute `remove_index` before creating deferrable unique constraints.

*Hiroyuki Ishii*
2023-03-10 16:09:32 +09:00
Rafael Mendonça França 049dfd4ccf
Remove deprecated `Tasks::DatabaseTasks.schema_file_type` 2023-03-03 00:38:27 +00:00
Rafael Mendonça França 96b9fd6f14
Remove deprecated `config.active_record.partial_writes` 2023-03-03 00:38:25 +00:00
Rafael Mendonça França 96c9db1b48
Remove deprecated `ActiveRecord::Base` config accessors 2023-03-03 00:38:24 +00:00
eileencodes 232aed8504
Allow configs_for to accept a custom hash key
Now that we support a way to register custom configurations we need to
allow applications to find those configurations. This change adds a
`config_key` option to `configs_for` to find db configs where the
configuration_hash contains a particular key.

I have also removed the deprecation for `include_replicas` while I was
in here to make the method signature cleaner. I've updated the upgrade
guide with the removal.
2023-02-28 12:12:08 -05:00
eileencodes 3d004435b4
Allow applications to register custom database configurations
Previously, applications could only have two types of database
configuration objects, `HashConfig` and `UrlConfig`. This meant that if
you wanted your config to implement custom methods you had to monkey
patch `DatabaseConfigurations` to take a custom class into account. This
PR allows applications to register a custom db_config handler so that
custom configs can respond to needed methods. This is especially useful
for tools like Vitess where we may want to indicate it's sharded, but
not give Rails direct access to that knowledge.

Using the following database.yml as an example:

```yaml
development:
  primary:
    database: my_db
  animals:
    database: my_animals_db
    vitess:
      sharded: 1
```

We can register a custom handler that will generate `VitessConfig`
objects instead of a `HashConfig` object in an initializer:

```ruby
ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|
  next unless config.key?(:vitess)

  VitessConfig.new(env_name, name, config)
end
```

and create the `VitessConfig` class:

```ruby
class VitessConfig < ActiveRecord::DatabaseConfigurations::UrlConfig
  def sharded?
    vitess_config.fetch("sharded", false)
  end

  private
    def vitess_config
      configuration_hash.fetch(:vitess_config)
    end
end
```

Now when the application is booted, the config with the `vitess` key
will generate a `VitessConfig` object where all others will generate a
`HashConfig`.

Things to keep in mind:

1) It is recommended but not required that these custom configs inherit
from Rails so you don't need to reimplement all the existing methods.
2) Applications must implement the configuration in which their config
should be used, otherwise first config wins (so all their configs
will be the custom one.)
3) The procs must support 4 arguments to accommodate `UrlConfig`. I am
thinking of deprecating this and forcing the URL parsing to happen in
the `UrlConfig` directly.
4) There is one tiny behavior change where when we have a nil url key in
the config hash we no longer merge it back into the configuration hash.
We also end up with a `HashConfig` instead of a `UrlConfig`. I think
this is fine because a `nil` URL is...useless.

Co-authored-by: John Crepezzi <john.crepezzi@gmail.com>
2023-02-28 10:12:28 -05:00
Carlos Antonio da Silva 0b32852878 Small tweaks on AR changelog [ci skip] 2023-02-24 09:50:45 -03:00
Jean Boussier 50edf85acd Fix a typo in activerecord/CHANGELOG 2023-02-24 11:58:44 +01:00
Jean Boussier 144518de1f Add missing CHANGELOG entries for #47463 and #47422 2023-02-24 10:03:07 +01:00
zzak c7e444e3b0
💅 changelog from #44803 2023-02-22 10:48:15 +09:00
sabrams86 e42d9f7066 Add support for include index option
Add support for including non-key columns in
btree indexes for PostgreSQL with the INCLUDE
parameter.

Example:

    def change
      add_index :users, :email, include: [:id, :created_at]
    end

Will result in:

    CREATE INDEX index_users_on_email USING btree (email) INCLUDE (id,
    created_at)

The INCLUDE parameter is described in the PostgreSQL docs:
  https://www.postgresql.org/docs/current/sql-createindex.html
2023-02-21 15:52:50 -07:00
Jean Boussier 3635d2d9cf YAMLColumn: use `YAML.safe_dump` if available
One particularly annoying thing with YAMLColumn type restriction
is that it is only checked on load.

Which means if your code insert data with unsupported types, the
insert will work, but now you'll be unable to read the record, which
makes it hard to fix etc.

That's the reason why I implemented `YAML.safe_dump` (https://github.com/ruby/psych/pull/495).

It applies exactly the same restrictions than `safe_load`, which means
if you attempt to store non-permitted fields, it will fail on insertion
and not on further reads, so you won't create an invalid record in your
database.
2023-02-13 14:39:43 +01:00
Rafael Mendonça França 25d52ab782
Fix typo 2023-02-02 17:10:37 +00:00
Jean Boussier 0ff9beba87 ActiveRecord::QueryLogs: handle invalid encoding
It can sometimes happen that `sql` is encoded in UTF-8 but contains
some invalid binary data of some sort.

When this happens `strip` end up raising an EncodingError.

Overall I think this strip is quite wasteful, so we might as well
just skip it.
2023-02-01 13:48:54 +01:00
Reid Lynch f61a679902 ActiveRecord::Relation#explain accepts options
For databases and adapters which support them (currently PostgreSQL
and MySQL), options can be passed to `explain` to provide more
detailed query plan analysis.
2023-01-24 09:24:43 -05:00
Ole Friis 06ef7a95ac Add ability to concatenate Arel.sql fragments 2023-01-19 09:27:05 +00:00
Alex Ghiculescu d092166347 `ActiveRecord::Base#signed_id`: raise if called on a new record 2023-01-18 13:05:47 -07:00
Adrianna Chang 56c5685324 Allow SQL warnings to be reported for MySQL and Postgres.
`ActiveRecord.db_warnings_action` can be used to configure the
action to take when a query produces a warning. The warning can be
logged, raised, or trigger custom behaviour provided via a proc.

`ActiveRecord.db_warnings_ignore` allows applications to set an
allowlist of SQL warnings that should always be ignored, regardless
of the configured action.

Co-authored-by: Paarth Madan <paarth.madan@shopify.com>
2023-01-17 11:58:56 -05:00
Danielius cfc0144832
Add regroup method 2023-01-14 12:08:46 +02:00
Leonardo Luarte González 7e95d3e653 Adds schema parameter into enable_extension
This patch tries to solve Heroku's new [PostgreSQL extension policy](https://devcenter.heroku.com/changelog-items/2446)
while keeping the migration and schema code idiomatic.

PostgreSQL adapter method `enable_extension` now allows to add an schema in its name.
The extension must be installed on another schema.

Usage:

`enable_extension('other_schema.hstore')`

The `enable_extension` can work with `schema` only if the given schema
already exists in the database.
2023-01-05 06:58:48 +00:00
George Claghorn 827ae3c449
ActiveRecord::Relation#none?/#any?/#one?: support pattern arg (#46728) 2022-12-22 08:21:54 +01:00
Jonathan Hefner d4c31bd849 Add ActiveRecord::Base::normalizes
`ActiveRecord::Base::normalizes` declares a normalization for one or
more attributes.  The normalization is applied when the attribute is
assigned or updated, and the normalized value will be persisted to the
database.  The normalization is also applied to the corresponding
keyword argument of finder methods.  This allows a record to be created
and later queried using unnormalized values.  For example:

  ```ruby
  class User < ActiveRecord::Base
    normalizes :email, with: -> email { email.strip.downcase }
  end

  user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n")
  user.email                  # => "cruise-control@example.com"

  user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")
  user.email                  # => "cruise-control@example.com"
  user.email_before_type_cast # => "cruise-control@example.com"

  User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")         # => true
  User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
  ```
2022-12-21 12:08:36 -06:00
Adrianna Chang 0b5a705e1b Hide changes to before_committed! behaviour behind config
As of https://github.com/rails/rails/pull/46525, the behaviour around
before_committed! callbacks has changed: callbacks are run on every
enrolled record in a transaction, even multiple copies of the same record.
This is a significant change that apps should be able to opt into in order
to avoid unexpected issues.
2022-12-15 11:43:51 -05:00
Eileen M. Uchitelle b94b9bd984
Merge pull request #46641 from ghiculescu/query-log-namespace
Query Logs: `namespaced_controller` tag should match `controller` format
2022-12-13 13:13:34 -05:00
Alex Ghiculescu 090d1acfe4 Query Logs: `namespaced_controller` tag should match `controller` format
Currently if you do this:

```ruby
config.active_record.query_log_tags = [:namespaced_controller]
```

A request that's processed by the `NameSpaced::UsersController` will log as `namespaced_controller='NameSpaced%3A%3AUsersController'`.

By contrast if you set the tag to `:controller` it would log as `controller='user'`, much nicer.

This PR makes the `:namespaced_controller` formatting more similar to `:controller` - it will now log as `namespaced_controller='name_spaced/users'`.
2022-12-12 10:31:00 -06:00
David Heinemeier Hansson d18fc32999
Use storage/ instead of db/ for sqlite3 db files (#46699)
* Use storage/ instead of db/ for sqlite3 db files

db/ should be for configuration only, not data. This will make it easier to mount a single volume into a container for testing, development, and even sqlite3 in production.
2022-12-12 08:32:12 +01:00
Joshua Young 8fd336927a [Fix: #46455] ActiveRecord::Calculations#ids plucks included associations IDs 2022-12-09 08:23:48 +05:30
Phil Pirozhkov 61464b0728 Don't use lower() for citext columns
In case when an index is present, using `lower()` prevents from using
the index.

The index is typically present for columns with uniqueness, and
`lower()` is added for `validates_uniqueness_of ..., case_sensitive: false`.

However, if the index is defined with `lower()`, the query without
`lower()` wouldn't use the index either.

Setup:
```
CREATE EXTENSION citext;
CREATE TABLE citexts (cival citext);
INSERT INTO citexts (SELECT MD5(random()::text) FROM generate_series(1,1000000));
```

Without index:
```
EXPLAIN ANALYZE SELECT * from citexts WHERE cival = 'f00';
 Gather  (cost=1000.00..14542.43 rows=1 width=33) (actual time=165.923..169.065 rows=0 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on citexts  (cost=0.00..13542.33 rows=1 width=33) (actual time=158.218..158.218 rows=0 loops=3)
         Filter: (cival = 'f00'::citext)
         Rows Removed by Filter: 333333
 Planning Time: 0.070 ms
 Execution Time: 169.089 ms
Time: 169.466 ms

EXPLAIN ANALYZE SELECT * from citexts WHERE lower(cival) = lower('f00');
 Gather  (cost=1000.00..16084.00 rows=5000 width=33) (actual time=166.896..169.881 rows=0 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on citexts  (cost=0.00..14584.00 rows=2083 width=33) (actual time=157.348..157.349 rows=0 loops=3)
         Filter: (lower((cival)::text) = 'f00'::text)
         Rows Removed by Filter: 333333
 Planning Time: 0.084 ms
 Execution Time: 169.905 ms
Time: 170.338 ms
```

With index:
```
CREATE INDEX val_citexts ON citexts (cival);

EXPLAIN ANALYZE SELECT * from citexts WHERE cival = 'f00';
 Index Only Scan using val_citexts on citexts  (cost=0.42..4.44 rows=1 width=33) (actual time=0.051..0.052 rows=0 loops=1)
   Index Cond: (cival = 'f00'::citext)
   Heap Fetches: 0
 Planning Time: 0.118 ms
 Execution Time: 0.082 ms
Time: 0.616 ms

EXPLAIN ANALYZE SELECT * from citexts WHERE lower(cival) = lower('f00');
 Gather  (cost=1000.00..16084.00 rows=5000 width=33) (actual time=167.029..170.401 rows=0 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on citexts  (cost=0.00..14584.00 rows=2083 width=33) (actual time=157.180..157.181 rows=0 loops=3)
         Filter: (lower((cival)::text) = 'f00'::text)
         Rows Removed by Filter: 333333
 Planning Time: 0.132 ms
 Execution Time: 170.427 ms
Time: 170.946 ms

DROP INDEX val_citexts;
```

With an index with `lower()` has a reverse effect, a query with
`lower()` performs better:
```
CREATE INDEX val_citexts ON citexts (lower(cival));

EXPLAIN ANALYZE SELECT * from citexts WHERE cival = 'f00';
 Gather  (cost=1000.00..14542.43 rows=1 width=33) (actual time=174.138..177.311 rows=0 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on citexts  (cost=0.00..13542.33 rows=1 width=33) (actual time=165.983..165.984 rows=0 loops=3)
         Filter: (cival = 'f00'::citext)
         Rows Removed by Filter: 333333
 Planning Time: 0.080 ms
 Execution Time: 177.333 ms
Time: 177.701 ms

EXPLAIN ANALYZE SELECT * from citexts WHERE lower(cival) = lower('f00');
                                                            QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on citexts  (cost=187.18..7809.06 rows=5000 width=33) (actual time=0.021..0.022 rows=0 loops=1)
   Recheck Cond: (lower((cival)::text) = 'f00'::text)
   ->  Bitmap Index Scan on lower_val_on_citexts  (cost=0.00..185.93 rows=5000 width=0) (actual time=0.018..0.018 rows=0 loops=1)
         Index Cond: (lower((cival)::text) = 'f00'::text)
 Planning Time: 0.102 ms
 Execution Time: 0.048 ms
(6 rows)
Time: 0.491 ms
```
2022-11-30 10:54:32 +03:00
Adrianna Chang dc8c086572 Extract `#sync_timezone_changes` method in AbstractMysqlAdapter
This enables subclasses to sync database timezone changes without overriding `#raw_execute`,
which removes the need to redefine `#raw_execute` in the `Mysql2Adapter` and other
adapters subclassing `AbstractMysqlAdapter`.

Co-authored-by: Paarth Madan <paarth.madan@shopify.com>
2022-11-29 11:21:39 -05:00
mishaschwartz 691dbf0997 do not write additional new lines when dumping sql migration versions 2022-11-28 08:49:01 -05:00
sampatbadhe b161c7ca50 update load_defaults 7.1 to config.load_defaults 7.1 2022-11-26 13:55:08 +05:30
Greg Navis 461d88a59b Fix composed_of freezing and duplication
composed_of values should be automatically frozen by Active Record.
This worked correctly when assigning a new value object via the writer,
but objects instantiated based on database columns were NOT frozen. The
fix consists of calling #dup and then #freeze on the cached value
object when it's added to the aggregation cache in #reader_method.

Additionally, values assigned via the accessor are duplicated and then
frozen to avoid caller confusion.
2022-11-25 17:36:12 +01:00
Phil Pirozhkov b39050e8d5 Fix incorrect caching of case-insensitivity
`false` values would not cache with `||=`, and `begin` would run each time.
2022-11-25 12:00:07 +01:00
Alfred Dominic 61b8253387 option to disable all methods that ActiveRecord.enum generates 2022-11-24 15:26:05 +04:00
fatkodima e5d15140d2 Avoid validating `belongs_to` association if it has not changed 2022-11-24 13:04:10 +02:00
George Claghorn 725ee79971 Allow resetting singular associations 2022-11-23 14:53:36 -05:00
Carlos Palhares e313fc5a4d
Permit YAML classes and unsafe load per attribute
Allow unsafe_load to override application setting

Process options on load

Add CHANGELOG entry
2022-11-23 18:25:06 +00:00
Rafael Mendonça França 2434e201cf
Merge PR #45696 2022-11-23 16:54:00 +00:00
Alex Ghiculescu 7b094755c8 Fix docs for Readonly Attributes changes
Co-authored-by: Petrik de Heus <petrik@deheus.net>
2022-11-21 10:22:32 -06:00
Rafael Mendonça França f2bbe6eb28
Merge PR #46105 2022-11-17 19:28:35 +00:00
Hartley McGuire 7b6720dfc8
Raise on assignment to readonly attributes
Previously, assignment would succeed but silently not write to the
database.

The changes to counter_cache are necessary because incrementing the
counter cache for a column calls []=. I investigated an approach to use
_write_attribute instead, however counter caches are expected to resolve
attribute aliases so write_attribute/[]= seems more correct.

Similarly, []= was replaced with _write_attribute in merge_target_lists
to skip the overriden []= and the primary key check. attribute_names
will already return custom primary keys so the primary_key check in
write_attribute is not needed.

Co-authored-by: Alex Ghiculescu <alex@tanda.co>
2022-11-16 17:14:54 -05:00
Rafael Mendonça França f7af67e8f5
Merge PR #45147 2022-11-14 23:32:37 +00:00
Hartley McGuire 9b7ae2b24a
Add filtering of encrypted attributes in #inspect
Previously, encrypted attributes could be added to an application's
filter_parameters which would filter the attribute values from logs.

This commit makes the add_to_filter_parameters additionally add
encrypted attributes to records' filter_attributes, which allows them
to be filtered when models are inspected (such as in the console).
2022-11-12 16:31:24 -05:00
Dave Morehouse e2c720fbb8 Allow unscoping of preload and eager_load associations
Adds the ability to unscope preload and eager_load associations.
This is the same functionality as `unscope(:includes)` which
may chose to use eager_loading or preloading based on the
overall query complexity. In cases where the type of association
loading is explicit (eager_load and preload), this allows for
unscoping the explicit association loading.  This is helpful when
taking an existing query and performing an aggregate when
has_many associations have explicitly asked for eager_load or
preload. In the example below, unscoping the two has_many
associations removes the extra preload query and eager_load
join.

        query.eager_load!(:has_many_association1)
        query.preload!(:has_many_association2)
        query.unscope(:eager_load, :preload).group(:id).select(:id)

There are also cases where depending on the aggregation
and select the explict preload fails when the select does not
include the preload association key. This issue led me to
write this fix.
2022-11-12 08:06:10 -06:00
Sean Denny 313a379a01 Add a build persistence method
Provides a wrapper for `new`, to provide feature parity with `create`s
ability to create multiple records from an array of hashes, using the
same notation as the `build` method on associations.

- Associations can create multiple objects from an array of hashes
- Associations can build multiple objects from an array of hashes
- Classes can create multiple objects from an array of hashes
- Classes can build multiple objects from an array of hashes (<- You are here)
2022-11-10 11:28:21 -05:00
Jean Boussier 7db044f385 Merge pull request #46243 from shouichi/clear-locking-column-on-dup
Clear locking column on #dup

Fix: #46243
2022-11-02 11:35:50 +01:00
Shouichi Kamiya 13d3fc9d32 Clear locking column on #dup
When duplicating records, we usually want to create a new record and
don't want to keep the original lock_version. Just like timestamp
columns are not copied.

Co-authored-by: Seonggi Yang <seonggi.yang@gmail.com>
Co-authored-by: Ryohei UEDA <ueda@anipos.co.jp>
2022-11-02 09:40:41 +09:00
Nikita Vasilevsky bf24af73ff Invalidate transaction as early as possible
This should allow framework to avoid issuing `ROLLBACK` statements
for cases when db has already rolled back the transaction
2022-11-02 00:05:44 +00:00
Nikita Vasilevsky 415e6b6391 Allow specifying columns to use in `ActiveRecord::Base` object queries
Renames `_primary_key_constraints_hash` private method to avoid implying
that it strictly represents a constraint based on the model primary key

Allows columns list used in query constraints to be configurable using
`ActiveRecord::Base.query_constraints` macro
2022-11-01 15:52:34 +00:00
Tommy Graves 26f316a855
Adds validate to foreign keys and check constraints in schema.rb 2022-10-25 19:34:39 -04:00
Adrianna Chang 8f780c58ea Allow adapter #execute methods to take allow_retry option
If a user is calling `#execute` directly with a SQL string, they can
also specify whether they'd like the query to be retried in the case
of a connection-related exception. By nature, this means that applications
looking to opt into retries across all queries can patch `#execute` to
call super with `allow_retry: true` instead of needing to reimplement the
method entirely.
2022-10-24 19:04:02 -04:00
modulitos e333bda876 Clarify ActiveRecord changelog for SQLCommenter
Forgot to update the changelog when we changed the default values for
`config.active_record.query_log_tags_format` from `:legacy` to
`:sqlcommenter`.

This change is a followup to: https://github.com/rails/rails/issues/46179
2022-10-22 22:27:58 -07:00
Ben Sheldon e32c7043d7
Do not trigger `after_commit :destroy` callback again on destroy if record previously was destroyed 2022-10-21 11:20:58 -07:00
Jonathan Hefner 02e351e48c Fix ciphertext_for for yet-to-be-encrypted values
Prior to this commit, `ciphertext_for` returned the cleartext of values
that had not yet been encrypted, such as with an unpersisted record:

  ```ruby
  Post.encrypts :body

  post = Post.create!(body: "Hello")
  post.ciphertext_for(:body)
  # => "{\"p\":\"abc..."

  post.body = "World"
  post.ciphertext_for(:body)
  # => "World"
  ```

This commit fixes `ciphertext_for` to always return the ciphertext of
encrypted attributes:

  ```ruby
  Post.encrypts :body

  post = Post.create!(body: "Hello")
  post.ciphertext_for(:body)
  # => "{\"p\":\"abc..."

  post.body = "World"
  post.ciphertext_for(:body)
  # => "{\"p\":\"xyz..."
  ```
2022-10-20 12:31:45 -05:00
Ryuta Kamizono 4136145819 Fixup CHANGELOGs [ci-skip] 2022-10-20 18:37:48 +09:00
Dooor 31c15b4791 Fix a bug where using groups and counts with long table names would return incorrect results.
Fixed a bug that caused the alias name of "group by" to be too long and the first half of the name would be the same in both cases if it was cut by max identifier length.

Fix #46285

Co-authored-by: Yusaku ONO <yono@users.noreply.github.com>
2022-10-20 16:15:45 +09:00
Jonathan Hefner c48a83020a Fix encryption of column default values
Prior to this commit, encrypted attributes that used column default
values appeared to be encrypted on create, but were not:

  ```ruby
  Book.encrypts :name

  book = Book.create!
  book.name
  # => "<untitled>"
  book.name_before_type_cast
  # => "{\"p\":\"abc..."
  book.reload.name_before_type_cast
  # => "<untitled>"
  ```

This commit ensures attributes with column default values are encrypted:

  ```ruby
  Book.encrypts :name

  book = Book.create!
  book.name
  # => "<untitled>"
  book.name_before_type_cast
  # => "{\"p\":\"abc..."
  book.reload.name_before_type_cast
  # => "{\"p\":\"abc..."
  ```

The existing "support encrypted attributes defined on columns with
default values" test in `encryptable_record_test.rb` shows the intended
behavior, but it was not failing without a `reload`.
2022-10-19 22:56:59 -05:00
eileencodes a93d8fe294
Deprecate delegation to connection handler from Base
In a multi-db world, delegating from `Base` to the handler doesn't make
much sense. Applications should know when they are dealing with a single
connection (Base.connection) or the handler which deals with multiple
connections. Delegating to the connection handler from Base breaks this
contract and makes behavior confusing. I think eventually a new object
will replace the handler altogether but for now I'd like to just
separate concerns to avoid confusion.
2022-10-19 10:20:37 -04:00
sampatbadhe 90e96e5122 Allow ActiveRecord::QueryMethods#reselect to accept a hash
Add ability to use hash with columns and aliases inside #reselect method similar to #select which introduced in https://github.com/rails/rails/pull/45612
2022-10-18 02:36:56 +05:30
Alan Guo Xiang Tan e6da3ebd6c
Validate options when managing columns and tables in migration
This commit adds a step to validate the options that are used when managing columns and tables in migrations.
The intention is to only validate options for new migrations that are added. Invalid options used in old migrations are silently ignored like they always have been.

Fixes #33284
Fixes #39230

Co-authored-by: George Wambold <georgewambold@gmail.com>
2022-10-11 15:31:22 +08:00
modulitos 6df894fd56 Add sqlcommenter formatting support on query logs
Co-authored-by: Iheanyi Ekechukwu <iekechukwu@gmail.com>
2022-09-27 14:38:35 -07:00
Eike Send 5ba8aa5854
Facilitate use of any regular ERB in database.yml
Commit 37d1429ab1 introduced the DummyERB to avoid loading the environment when
running `rake -T`.

The DummyCompiler simply replaced all output from `<%=` with a fixed string and
removed everything else. This worked okay when it was used for YAML values.
When using `<%=` within a YAML key, it caused an error in the YAML parser,
making it impossible to use ERB as you would expect. For example a
`database.yml` file containing the following should be possible:

  development:
    <% 5.times do |i| %>
    shard_<%= i %>:
      database: db/development_shard_<%= i %>.sqlite3
      adapter: sqlite3
    <% end %>

Instead of using a broken ERB compiler we can temporarily use a
`Rails.application.config` that does not raise an error when configurations are
accessed which have not been set as described in #35468.

This change removes the `DummyCompiler` and uses the standard `ERB::Compiler`.
It introduces the `DummyConfig` which delegates all known configurations to the
real `Rails::Application::Configuration` instance and returns a dummy string for
everything else. This restores the full ERB capabilities without compromising on
speed when generating the rake tasks for multiple databases.

Deprecates `config.active_record.suppress_multiple_database_warning`.
2022-09-27 17:07:40 +02:00
Petrik 39a20095bf Add table to error for duplicate column definitions
If a migration defines duplicate columns for a table the error message
should show which table it concerns.
2022-09-23 15:40:37 +02:00
Sam Bostock b85ee91633
Fix virtual datetime default precision
Prior to this change

    t.virtual :column_name, type: :datetime

would erroneously produce the same result as

    t.virtual :column_name, type: :datetime, precision: nil

This is because the code path for `virtual` skipped the default lookup:

- `t.datetime` is delegated to the `column` method
  - `column` sees `type == :datetime` and sets a default `precision` is none was given
  - `column` calls `new_column_definition` to add the result to `@columns_hash`
- `t.virtual` is delegated to the `column` method
  - `column` sees `type == :virtual`, not `:datetime`, so skips the default lookup
  - `column` calls `new_column_definition` to add the result to `@columns_hash`
    - `new_column_definition` sees `type == :virtual`, so sets `type = options[:type]`

By moving the default lookup, we get consistent code paths:

- `t.datetime` is delegated to the `column` method
  - `column` calls `new_column_definition` to add the result to `@columns_hash`
    - `new_column_definition` sees `type == :datetime` and sets a default `precision` is none was given
- `t.virtual` is delegated to the `column` method
  - `column` calls `new_column_definition` to add the result to `@columns_hash`
    - `new_column_definition` sees `type == :virtual`, so sets `type = options[:type]`
    - `new_column_definition` sees `type == :datetime` and sets a default `precision` is none was given
2022-09-22 17:58:25 -04:00
Adrianna Chang b00ca21999 Use connection from `#with_raw_connection` in `#quote_string`.
This ensures we hook into the retry logic for connection-related exceptions
that `#with_raw_connection` provides.
2022-09-22 17:07:55 -04:00
Shouichi Kamiya 364939c2b1 Add `expires_at` option to `signed_id`
Problem:

Though, the `MessageVerifier` that powers `signed_id` supports both
`expires_in` and `expires_at`, `signed_id` only supports `expires_in`.
Because of this, generating signed_id that expires at a certain time is
somewhat tedious. Imagine issuing a coupon that is valid only for a
day.

Solution:

Add `expires_at` option to `signed_id` to generate signed ids that
expire at the given time.
2022-09-22 22:39:55 +02:00
Adrianna Chang 4d13f05a2e Take into account timeout limit when retrying queries
Building on the work done in #44576 and #44591, we extend the logic that automatically
reconnects broken db connections to take into account a timeout limit. This ensures
that retries + reconnects are slow-query aware, and that we don't retry queries
if a given amount of time has already passed since the query was first tried.

This value will default to 5 seconds, but can be adjusted via the `connection_retry_timeout`
config.
2022-09-22 14:29:33 -04:00
Aaron Patterson 5abb45d53a Dup and freeze complex types when making query attributes
This avoids problems when complex data structures are mutated _after_
being handed to ActiveRecord for processing.  For example false hits in
the query cache.

Fixes #46044
2022-09-19 09:41:39 +02:00
Petrik d14662a5ae Tiny copy fix in CHANGELOGs [ci-skip] 2022-09-17 12:54:43 +02:00
Petrik ed3b92b38f Add ssl-mode option to dbconsole command and MySQLDatabaseTasks
According to the MySQL documentation, database connections default to
ssl-mode=PREFERRED. But PREFERRED doesn't verify the server's identity:

    The default setting, --ssl-mode=PREFERRED, produces an encrypted
    connection if the other default settings are unchanged. However, to
    help prevent sophisticated man-in-the-middle attacks, it is
    important for the client to verify the server’s identity. The
    settings --ssl-mode=VERIFY_CA and --ssl-mode=VERIFY_IDENTITY are a
    better choice than the default setting to help prevent this type of
    attack. VERIFY_CA makes the client check that the server’s
    certificate is valid. VERIFY_IDENTITY makes the client check that
    the server’s certificate is valid, and also makes the client check
    that the host name the client is using matches the identity in the
    server’s certificate.

https://dev.mysql.com/doc/refman/8.0/en/using-encrypted-connections.html

However both the Rails::DBConsole command and the MySQLDatabaseTasks
ignore the ssl-mode option, making the connection fallback to PREFERRED.

Adding ssl-mode to the forwarded options makes sure the expected mode is
passed to the connection.
2022-09-15 19:20:16 +02:00
eileencodes 93ddf338a0
Move InternalMetadata to an independent object
Followup to #45908 to match the same behavior as SchemaMigration

Previously, InternalMetadata inherited from ActiveRecord::Base. This is
problematic for multiple databases and resulted in building the code in
AbstractAdapter that was previously there. Rather than hacking around
the fact that InternalMetadata inherits from Base, this PR makes
InternalMetadata an independent object. Then each connection can get it's
own InternalMetadata object. This change required defining the methods
that InternalMetadata was depending on ActiveRecord::Base for (ex
create!). I reimplemented only the methods called by the framework as
this class is no-doc's so it doesn't need to implement anything beyond
that. Now each connection gets it's own InternalMetadata object which
stores the connection.

This change also required adding a NullInternalMetadata class for cases
when we don't have a connection yet but still need to copy migrations
from the MigrationContext. Ultimately I think this is a little weird -
we need to do so much work to pick up a set of files? Maybe something to
explore in the future.

Aside from removing the hack we added back in #36439 this change will
enable my work to stop clobbering and depending directly on
Base.connection in the rake tasks. While working on this I discovered
that we always have a ActiveRecord::InternalMetadata because the
connection is always on Base in the rake tasks. This will free us up
to do less hacky stuff in the migrations and tasks.

Both schema migration and internal metadata are blockers to removing
`Base.connection` and `Base.establish_connection` from rake tasks, work
that is required to drop the reliance on `Base.connection` which will
enable more robust (and correct) sharding behavior in Rails..
2022-09-12 09:17:02 -04:00
Rafael Mendonça França 91a2ae5e59
Remove CHANGELOG entry for change only existing in main
The issue fixed by the commit that introduced that entry only existed
in the main branch, so it isn't really a released change worthy of a
CHANGELOG entry.
2022-09-09 22:56:36 +00:00
Rafael Mendonça França 9f372c94ea
Merge PR #44438 2022-09-09 21:14:08 +00:00
admin 62c358595c
improve "in_order_of" to allow string column name 2022-09-09 21:46:04 +03:00
Iliana Hadzhiatanasova a0fd15ee7e Default prepared_statements to false for mysql2 adapter 2022-09-09 16:21:33 +01:00
eileencodes 436277da88
Move SchemaMigration to an independent object
Previously, SchemaMigration inherited from ActiveRecord::Base. This is
problematic for multiple databases and resulted in building the code in
AbstractAdapter that was previously there. Rather than hacking around
the fact that SchemaMigration inherits from Base, this PR makes
SchemaMigration an independent object. Then each connection can get it's
own SchemaMigration object. This change required defining the methods
that SchemaMigration was depending on ActiveRecord::Base for (ex
create!). I reimplemented only the methods called by the framework as
this class is no-doc's so it doesn't need to implement anything beyond
that. Now each connection gets it's own SchemaMigration object which
stores the connection. I also decided to update the method names (create
-> create_version, delete_by -> delete_version, delete_all ->
delete_all_versions) to be more explicit.

This change also required adding a NullSchemaMigraiton class for cases
when we don't have a connection yet but still need to copy migrations
from the MigrationContext. Ultimately I think this is a little weird -
we need to do so much work to pick up a set of files? Maybe something to
explore in the future.

Aside from removing the hack we added back in #36439 this change will
enable my work to stop clobbering and depending directly on
Base.connection in the rake tasks. While working on this I discovered
that we always have a `ActiveRecord::SchemaMigration` because the
connection is always on `Base` in the rake tasks. This will free us up
to do less hacky stuff in the migrations and tasks.
2022-09-08 11:32:32 -04:00
eileencodes 69396b75c9
Make connection_pool_list take an explicit argument
Following on #45924 I realized that `all_connection_pools` and
`connection_pool_list` don't make much sense as separate methods and
should follow the same deprecation as the other methods on the handler
here. So this PR deprecates `all_connection_pools` in favor of
`connection_pool_list` with an explicit argument of the role or `:all`.
Passing `nil` will throw a deprecation warning to get applications to
be explicit about behavior they expect.
2022-09-07 14:44:18 -04:00
eileencodes 74cb960e66
Fix bug in connection handler methods using all pools
Previously when I implemented multiple database roles in Rails there
were two handlers so it made sense for the methods
`active_connections?`, `clear_active_connections!`,
`clear_reloadable_connections!`, `clear_all_connections!`, and
`flush_idle_connections!` to only operate on the current (or passed)
role and not all pools regardless of role. When I removed this and moved
all the pools to the handler maintained by a pool manager, I left these
methods as-is to preserve the original behavior.

This made sense because I thought these methods were only called by
applications and not called by Rails. I realized yesterday that some of
these methods (`flush_idle_connections!`, `clear_active_connections!`,
and `clear_reloadable_connections!` are all called on boot by the
Active Record railtie.

Unfortunately this means that applications using multiple databases
aren't getting connections flushed or cleared on boot for any connection
but the writing ones.

The change here continues existing behavior if a role like reading is
passed in directly. Otherwise if the role is `nil` (which is the new
default` we fall back to all connections and issue a deprecation
warning. This will be the new default behavior in the future. In order
to easily allow turning off the deprecation warning I've added an `:all`
argument that will use all pools but no warning. The deprecation warning
will only fire if there is more than one role in the pool manager,
otherwise we assume prior behavior.

This bug would have only affected applications with more than one role
and only when these methods are called outside the context of a
`connected_to` block. These methods no longer consider the set
`current_role` and applications need to be explicit if they don't want
these methods to operate on all pools.
2022-09-07 13:42:23 -04:00
alextrueman f4cfc2acdd Allow AR::QueryMethods#select to accept a hash
Add ability to use hash with columns and aliases inside #select method.

    Post
      .joins(:comments)
      .select(
        posts: { id: :post_id, title: :post_title },
        comments: { id: :comment_id, body: :comment_body}
      )

    instead

    Post
      .joins(:comments)
      .select(
        "posts.id as post_id, posts.title as post_title,
        comments.id as comment_id, comments.body as comment_body"
      )

Co-authored-by: Josef Šimánek <193936+simi@users.noreply.github.com>
Co-authored-by: Jean byroot Boussier <19192189+casperisfine@users.noreply.github.com>
2022-09-02 11:00:58 +02:00
Jonathan Hefner e45947328e Fix typo in CHANGELOG [ci-skip]
Follow-up to #42650.
2022-08-25 11:54:13 -05:00
Jacopo 2f5136a3be Normalize virtual attributes on `ActiveRecord::Persistence#becomes`
When source and target classes have a different set of attributes adapts
attributes such that the extra attributes from target are added.

Fixes #41195

Co-authored-by: SampsonCrowley <sampsonsprojects@gmail.com>
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2022-08-24 22:51:57 +02:00
Jonathan Hefner 18f8c6ac9b Add CHANGELOG entry for #45670 [ci-skip] 2022-08-17 11:51:31 -05:00
Iliana Hadzhiatanasova 79096618f0 Optimize add_timestamps to use a single SQL statement 2022-08-11 19:12:03 +03:00
Aram Greenman affb8cf2fe Deprecate quoting ActiveSupport::Duration as an integer 2022-08-04 09:15:58 -07:00
Alex Ghiculescu bd0fdc8094 Add `drop_enum` command for Postgres 2022-08-03 18:50:43 -05:00
eileencodes 25f97a66bd
Add support for `if_exists` option when removing a check constraint
The `remove_check_constraint` method now accepts an `if_exists` option. If set
to true an error won't be raised if the check constraint doesn't exist.

This commit is a combination of PR #45726 and #45718 with some
additional changes to improve wording, testing, and implementation.

Usage:

```ruby
remove_check_constraint :products, name: "price_check", if_exists: true
```

Fixes #45634

Co-authored-by: Margaret Parsa <mparsa@actbluetech.com>
Co-authored-by: Aditya Bhutani <adi_bhutani16@yahoo.in>
2022-08-03 14:39:54 -04:00
Jean Boussier 023a3eb3c0 find_or_create_by: handle race condition by finding again
Using `create_or_find_by` in codepaths where most of the time
the record already exist is wasteful on several accounts.

`create_or_find_by` should be the method to use when most of the
time the record doesn't already exist, not a race condition safe
version of `find_or_create_by`.

To make `find_or_create_by` race-condition free, we can search
the record again if the creation failed because of an unicity
constraint.

Co-Authored-By: Alex Kitchens <alexcameron98@gmail.com>
2022-08-02 09:58:26 +02:00
Matthew Draper 1adb6170d5 Add changelog entries for #44576 and #44591 2022-07-30 06:09:12 +09:30
fatkodima 515a9215d1 Avoid removing a PostgreSQL extension when there are dependent objects 2022-07-22 15:17:18 +03:00
Michael Siegfried 8fe1bd555f Accept nested functions in Dangerous Query Methods
Mailing list thread: https://discuss.rubyonrails.org/t/feature-proposal-accept-nested-functions-w-r-t-dangerous-query-methods/78650

*Summary*
I think there’s an opportunity to reduce additional false positives for
Dangerous Query Method deprecations/errors.

*Nested Functions*
Similar to https://github.com/rails/rails/pull/36448, it seems
reasonable to allow functions that accept other functions (e.g.
`length(trim(title))`).

*Background*
* PR accepting non-nested functions: https://github.com/rails/rails/pull/36448
* Deep background on deprecation and false positives: https://github.com/rails/rails/issues/32995
* Constants: `COLUMN_NAME` for the first and `COLUMN_NAME_WITH_ORDER` for both
2022-07-13 11:52:01 -07:00
Ben Sheldon 8fceabd1e8 Defer constant loading of `ActiveRecord::DestroyAssociationAsyncJob` via a String instead of a class constant
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2022-07-13 11:58:20 -05:00
Jean Boussier 05fdb3edfd ActiveRecord::Store encode store as a regular Hash
Fix: https://github.com/rails/rails/issues/45585

There's no benefit in serializing it as HWIA, it requires
to allow that type for YAML safe_load and takes more space.

We can cast it back to a regular hash before serialization.
2022-07-13 18:30:37 +02:00
Yasuo Honda 2cf8f37d50
Merge pull request #44601 from ghiculescu/time-zone-aware-type-postgres
Add `timestamptz` as a time zone aware type for PostgreSQL
2022-07-11 08:23:04 +09:00
Alex Ghiculescu 2f52610c49
Missing author on changelog entry for #44189
cc @jonathanhefner
2022-07-10 15:33:50 -05:00
Alex Ghiculescu 75c406d774 Make `timestamptz` a time zone aware type for Postgres
https://github.com/rails/rails/pull/41395 added support for the `timestamptz` type on the Postgres adapter.

As we found [here](https://github.com/rails/rails/pull/41084#issuecomment-1056430921) this causes issues because in some scenarios the new type is not considered a time zone aware attribute, meaning values of this type in the DB are presented as a `Time`, not an `ActiveSupport::TimeWithZone`.

This PR fixes that by ensuring that `timestamptz` is always a time zone aware type, for Postgres users.
2022-07-10 15:32:18 -05:00
Jonathan Hefner d44e786d21 Add CHANGELOG entry for #44189 [ci-skip] 2022-07-08 14:54:42 -05:00
fatkodima 620f247829 Optimize Active Record batching for whole table iterations 2022-07-06 00:21:39 +03:00
Vlado Cingel 098b0eb5db `.with` query method added.
Construct common table expressions with ease and get `ActiveRecord::Relation` back.
2022-07-01 17:44:51 +02:00
Rafael Mendonça França 92fa470aaa
Copy edit the CHANGELOG
Active Record names has space between the words.
2022-06-29 22:14:48 +00:00
eileencodes adb64db43d
Only remove connection for an existing pool if the config is different
Previously Rails would always remove the connection if it found a
matching class in the pool manager. Therefore if
`ActiveRecord::Base.establish_connection` was called with the same
config, each time it was called it would be clobbered, even though the
config hasn't changed and the existing connection is prefectly fine. As
far as I can tell from conversations and reading the history this
functionality was added for ActiveRecord tests to be able to clobber the
connection and use a new config, then re-establish the old connection.
Essentially outside Rake tasks and AR tests, this functionality doesn't
have a ton of value.

On top of not adding a ton of value, this has resulted in a few bugs. In
Rails 6.0 I made it so that if you established a connection on
`ApplicationRecord` Rails would treat that connection the same as
`ActiveRecord::Base.` The reason for this is that the Railtie
establishes a connection on boot to the first database, but then if
you're using multiple databases you're calling `connects_to` in your
`ApplicationRecord` or primary abstract class which essentially doubles
your connections to the same database. To avoid opening 2 connections to
the same database, Rails treats them the same.

However, because we have this code that removes existing connections,
when an application boots, `ApplicationRecord` will clobber the
connection that the Railtie established even though the connection
configs are the same.

This removal of the connection caused bugs in migrations that load up a
model connected to `ApplicationRecord` (ex `Post.first`) and then calls
`execute("SELECT 1")` (obviously a simplified example). When `execute`
runs the connection is different from the one opened to run the
migration and essentially it is lost when the `remove_connection` code
is called.

To fix this I've updated the code to only remove the connection if the
database config is different. Ultimately I'd like to remove this code
altogether but to do that we first need to stop using
`Base.establish_connection` in the rake tasks and tests. This will fix
the major bugs until I come up with a solution for the areas that
currently need to call `establish_connection` on Base.

The added benefit of this change is that if your app is calling
`establish_connection` multiple times with the same config, it is now
3x faster than the previous implementation because we can return the
found pool instead of setting it up again. To benchmark this I
duplicated the `establish_connection` method to use the new behavior
with a new name.

Benchmark script:

```ruby
require "active_record"
require "logger"
require "benchmark/ips"

config_hash = { "development" => { "primary" => { "adapter" => "mysql2", "username" => "rails", "database" => "activerecord_unittest"}}}
ActiveRecord::Base.configurations = config_hash

db_config = ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary")

p "Same model same config"
ActiveRecord::Base.connected_to(role: :writing, prevent_writes: true) do
  Benchmark.ips do |x|
    x.report "establish_connection with remove" do
      ActiveRecord::Base.establish_connection(db_config)
    end

    x.report "establish_connection without remove" do
      ActiveRecord::Base.establish_connection_no_remove(db_config)
    end

    x.compare!
  end
end
```

Benchmark results:

```
Warming up --------------------------------------
establish_connection with remove
                         4.677k i/100ms
establish_connection without remove
                        19.501k i/100ms
Calculating -------------------------------------
establish_connection with remove
                         41.252k (±11.3%) i/s -    205.788k in   5.075525s
establish_connection without remove
                        179.205k (± 6.9%) i/s -    897.046k in   5.029742s

Comparison:
establish_connection without remove:   179205.1 i/s
establish_connection with remove:    41252.3 i/s - 4.34x  (± 0.00) slower
```

Other changes:

1) sqlite3 now disconnects and reconnects the connection when `purge` is
called. This is necessary now that a new connection isn't created
everyt time `establish_connection` is called. Without this change to
purge the new database is left in an inaccessible state causing a
readonly error from the sqlite3 client. This wasn't happening in mysql
or postgres because they were already reconnecting the db connection.
2) I added `remove_connection` to tests that use `ApplicationRecord`.
This is required because `ApplicationRecord` or any class that is a
`primary_abstract_class` will be treated the same as
`ActiveRecord::Base`. This is fine in applications because they are
shared connections, but in the AR test environment, we don't want those
connnections to stick around (we want AR::Base back).
3) In the async tests I removed 2 calls to `establish_connection`. These
were causing sqlite3 tests to leak the state of async_executor because
it's stored on the connection. I'm not sure why these were calling
`establish_connection` but it's not necessary and was leaking state when
now that we are no longer removing the connection.

Fixes: #41855
Fixes: #41876
Fixes: #42873
Fixes: #43004
2022-06-29 11:25:17 -04:00
Ben Sheldon [he/him] 660fee087d
Allow db:prepare to load schema if database already exists but is empty; also dumps schema after migrations 2022-06-28 06:36:24 -07:00
Wojciech Wnętrzak 73b1a153b5
Fix supporting timezone awareness for `tsrange` and `tstzrange` array columns.
Before the fix, the error was thrown "TypeError: can't iterate from ActiveSupport::TimeWithZone".
2022-06-26 12:29:34 +02:00
Yasuo Honda 681ada1879 Remove trailing whitespaces of Active Record CHANGELOG
Follow up #45280
There are couple of pull requests that remove these trailing spaces.
Changing the trailing whitespaces is not related to them.
2022-06-26 17:10:31 +09:00
Adrianna Chang 6673d8ef3b Delegate migration methods to strategy object
The default strategy will continue to forward messages to the connection adapter,
but applications can configure a custom strategy class to use instead.
2022-06-23 09:14:02 -04:00
Paulo Barros db82002f2b
Add adapter option disallowing foreign keys 2022-06-20 11:11:46 +02:00
HParker 3a04c7b339 Add configurable deprecation warning for singular associations
This removes the singularize from `where` which runs on all `expand_from_hash` keys which might be reflections or column names. This saves a lot of time by avoiding singularizing column names.

Previously in https://github.com/rails/rails/pull/45163 the singularize was removed entirely. after some reflection, I think it is better to at least give a warning for one release since `where` is a very popular API and the problems you can run into with incorrect relation could be hard to debug.

Configurable with `ActiveRecord::Base.allow_deprecated_singular_assocaitions_name = false` / `config.active_record.allow_deprecated_singular_assocaitions_name = false`
2022-06-16 09:14:12 -07:00
fatkodima 21a6dbd313 Enable strict strings mode for `SQLite3Adapter`
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2022-06-14 23:59:17 +03:00
Cameron Bothner 936a862f3c
Run transactional callbacks on instances most likely to match DB state 2022-06-14 13:34:25 -04:00
Austen Madden a237867e8f Reset cache_versions on relation
Currently, when #reset is called on a relation object it does not reset
the cache_versions ivar. This can lead to a confusing and buggy
situation where despite having the correct data the relation is still
reporting a stale cache_version. Resetting this ivar along with the
other relation state corrects this situation.

Update test assertion

Assert the specific cache_version matches the latest .all relation

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2022-06-14 10:21:01 -04:00
Alex Robbin 1ceffeb4d9
adds support for exclusion constraints (PostgreSQL-only)
```ruby
add_exclusion_constraint :invoices, "daterange(start_date, end_date) WITH &&", using: :gist, name: "invoices_date_overlap"
remove_exclusion_constraint :invoices, name: "invoices_date_overlap"
```

See PostgreSQL's [`CREATE TABLE ... EXCLUDE ...`](https://www.postgresql.org/docs/12/sql-createtable.html#SQL-CREATETABLE-EXCLUDE) documentation for more on exclusion constraints.
2022-06-14 08:09:47 -04:00
Alex Ghiculescu 08dc02b005 `change_column_null` should raise if a non-boolean 3rd argument is provided
Currently if you provide a non-boolean argument, `change_column_null` will treat it as truthy and make your column nullable. This might not be what you want. For example, I've noticed this happen a few times, where someone assumes that `change_column_null` and `change_column_default` work the same:

```ruby
change_column_default(:posts, :state, from: nil, to: "draft")
change_column_null(:posts, :state, from: true, to: false)
```

Reading the migration you would expect that the default is now "draft" and the column doesn't accept nulls. But actually, the "null" argument is `{ from: true, to: false }` which is truthy, so now the column accepts nulls. If you aren't paying close attention to the migration output you might miss this.

I think we can protect users here by having `change_column_null` require the 3rd argument to be `true` or `false` and raising an error otherwise. This PR implements that, for migrations created on Rails 7.1 onward.
2022-06-13 13:46:12 -05:00
fatkodima 1ec879d02b Enforce limit on table names length 2022-06-13 14:10:14 +03:00
Eddie Lebow d5cbc24594
Adjust minimum MariaDB version for CHECK_CONSTRAINTS
https://mariadb.com/kb/en/information-schema-check_constraints-table/

on-behalf-of: @Cofense <oss@cofense.com>
2022-06-12 00:37:01 -04:00