PR #23733 was supposed to deprecate and remove the ability to compare
Hash objects with AC::Parameters objects. Unfortunately it seems that
we still accidentally support that.
This PR adds a deprecation warning so that we can remove it in the
future.
The default message would not tell you what the actual value is, just
what it expected it to have changed to or from.
It now tells you what the actual value is, similar to the output you'd
get from a matcher such as `assert_equal`
All validations are called on `#save` by default.
The Absence, Acceptance, Presence validators don't do anything special,
so there is no reason to mention they are called on `#save` by default.
Instead we can mention all validations are called in `#save` by default
in ActiveRecord::Validations.
Co-authored-by: Gannon McGibbon <gannon@hey.com>
Make it clearer that in the ActiveRecord AbsenceValidator, the
associated object is not _only_ absent if it is marked for destruction.
For the ActiveRecord PresenceValidator we can point to the ActiveModel
validations, like we do for other validations as well. This allows us to
remove some duplicated documentation.
After af7428c4ac the yarn install
instructions was dropped from bin/setup. This commmit adds it into
the setup script again if the user is not using importmap.
`validates_associated` makes sure that passed associations are validated
everytime the record is saved. This is unlike other validations that
validate an attribute/association has a certain value.
Typically you won't call:
validates :books, associated: true
By grouping `validates_associated` with `validates_with` and
`validates_each` it's made clearer `validates_associated` is a bit
different.
With this change the validations are sorted alphabetically.
In https://github.com/rails/rails/pull/43036 an optimisation was applied
to ActiveModel#Serialization to speed up the generation of a
serialized_hash by avoiding loading the subjects attributes by using an
attribute_names method. A fallback method,
ActiveModel::Serialization#attribute_names` was added as #attribute_names
isn't part of the public API of ActiveModel.
Unfortunately, this fallback method happens to override the ActiveRecord
method (as ActiveModel::Serialization is a later mixin than
ActiveRecord::AttributeMethods), so this change didn't actually provide
an optimisation - the full attribute data was loaded as per [1]
This change also, in our case, produced some severe performance issues
as it introduced an N+1 query in a situation where we had one gem,
Globalize [2], which adds in dynamic attributes that are loaded by a query;
and another gem, Transitions [3], that checks attribute names at
initialization. The combination of these meant that for every model that
was initialized an extra query would run - no matter what includes or
eager_load steps were in place. This rapidly hindered our applications'
performance and meant we had to rollback the Rails 7 upgrade.
Following rafaelfranca's suggestion [4] this adds a
`attribute_names_for_serialization` method to Serialization modules in
ActiveRecord and ActiveModel. This allows the ActiveRecord one to
override the ActiveModel fallback and thus be optimised.
Some basic benchmarks of this follow - they use code from
https://github.com/ollietreend/rails-demo and have some pretty large
arrays set as serialized attributes [5] to demonstrate impacts.
Loading attribute names:
Rails 7.0.2.3
```
> Benchmark.ms { Widget.all.map(&:attribute_names) }
Widget Load (131.1ms) SELECT "widgets".* FROM "widgets"
=> 20108.852999983355
```
This patch
```
> Benchmark.ms { Widget.all.map(&:attribute_names) }
Widget Load (144.0ms) SELECT "widgets".* FROM "widgets"
=> 237.96699999365956
```
Using serializable_hash:
Rails 7.0.2.3
```
> widgets = Widget.all.to_a; Benchmark.ms { widgets.map { |w| w.serializable_hash(only: []) } }
Widget Load (133.3ms) SELECT "widgets".* FROM "widgets"
=> 22071.45000001765
```
This patch
```
> widgets = Widget.all.to_a; Benchmark.ms { widgets.map { |w| w.serializable_hash(only: []) } }
Widget Load (83.5ms) SELECT "widgets".* FROM "widgets"
=> 67.9039999959059
```
[1]: eeb2cfb686/activemodel/lib/active_model/serialization.rb (L151-L154)
[2]: https://github.com/globalize/globalize
[3]: https://github.com/troessner/transitions
[4]: https://github.com/rails/rails/pull/44770#pullrequestreview-922209612
[5]: 525f88887b/db/seeds.rb
* Remove outdated information
* Clean up language and sentence structure to be clearer
* Remove commands that are no longer necessary
* Add note about how to move past the native extension issues with
mysql2 since it's become a big problem.
Condition arguments are escaped to prevent SQL injection, SQL LIKE
wildcards (i.e., `%` and `_`) are not escaped. But there are no
description about SQL LIKE escape in the rails querying guide. So,
this adds a description about SQL LIKE escape to the guide.