There are assertions that expected/actual arguments are passed in the
reversed order by mistake. Enabling the LiteralAsActualArgument rule
prevents this mistake from happening.
The existing tests were auto-corrected by rubocop with a bit of
indentation adjustment.
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
`undefine_attribute_methods` now removes alias attribute methods along
with attribute methods. This commit changes `define_attribute_methods` to
redefine methods back if any alias attributes were declared which provides
applications and libraries an option to bring the alias methods back
after using `undefine_attribute_methods`.
`8a5cf4cf4415ae1cdad7feecfb27149c151b0b10` made changes to `to_key` in order
to support composite identifiers. This commit adds CHANGELOG entries for those.
We ran into a few cases at GitHub where we were using alias_attribute
incorrectly and the new behavior either didn't warn or raised an unclear
deprecation warning. This attempts to add clarity to the deprecation reason
when you try to alias something that isn't actually an attribute.
Previously, trying to alias a generated attribute method, such as `attribute_in_database`, would
still hit `define_proxy_call`, because we were only checking the owner of the target method.
In the future, we should probably raise if you try to use alias_attribute for a non-attribute.
Note that we don't raise the warning for abstract classes, because the attribute may be implemented
by a child class. We could potentially figure out a way to raise in these cases as well, but this
hopefully is good enough for now.
Finally, I also updated the way we're setting `local_alias_attributes` when `alias_attribute` is
first called. This was causing problems since we now use `alias_attribute` early in the
`load_schema!` call for some models: https://buildkite.com/rails/rails/builds/98910
The current implementation of _to_partial_path composes the part of two bits, `collection' and `element'.
ActiveModel::Name also contains these fields, and they are derived the same way _to_partial_path does it.
However, _to_partial_path doesn't use the information in model_name, and solely relies on its own computations instead.
This works for all standard cases, but not necessarily for models that provide a non-standard model_name.
This commit fixes that and has _to_partial_path use model_name if the class responds to it.
This commit suppresses the `DEPRECATION WARNING: Support for `config.active_support.cache_format_version = 6.1`
has been deprecated and will be removed in Rails 7.2.` warning at `RailtieTest`
This commit sets `config.active_support.cache_format_version = 7.1` explicitly for `RailtieTest`
because https://github.com/rails/rails/pull/48598 deprecates `active_support.cache_format_version = 6.1` and still the default format_version is 6.1, I think this is intended.
4ac237de74/activesupport/lib/active_support/cache.rb (L55)
```
@format_version = 6.1
```
\### Steps to reproduce
```
git clone https://github.com/rails/rails
cd rails/activemodel
bundle
bin/test test/cases/railtie_test.rb:21
```
\### Without this commit
```
$ bin/test test/cases/railtie_test.rb:21
Run options: --seed 36872
\# Running:
DEPRECATION WARNING: Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.
Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
for more information on how to upgrade.
(called from block (3 levels) in run at /home/yahonda/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/minitest-5.19.0/lib/minitest/test.rb:94)
.
Finished in 0.321429s, 3.1111 runs/s, 3.1111 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
$
```
\### With this commit
```
$ bin/test test/cases/railtie_test.rb:21
Run options: --seed 65282
\# Running:
Finished in 0.006108s, 0.0000 runs/s, 0.0000 assertions/s.
0 runs, 0 assertions, 0 failures, 0 errors, 0 skips
$
```
This commit allows customizing the delimiter used by `to_param` when
`to_key` returns multiple value. This unblocks supporting more varieties
of composite primary key types in Active Record.
In `1818beb3a3ea5fdb498095d4885f8a7e512f24ca` Rails changed the target
where alias attribute methods are defined. It lead to
`undefine_attribute_methods` to clean alias attribute methods along with
the attribute methods. It was an intended behavior change but it wasn't
properly documented and tested. This commit clarifies the new behavior
in the Active Model changelog along with covering the behavior with tests.
This commit adds support for composite identifiers in `to_key`.
Rails 7.1 adds support for composite primary key which means that
composite primary key models' `#id` method returns an `Array` and
`to_key` needs to avoid double-wrapping the value.
Because we're using a class_attribute to track all of the attribute_aliases,
each subclass was regenerating the parent class methods, causing some unexpected
deprecation messages.
Instead, we can use a class instance variable to track the attributes aliased locally
in that particular subclass. We then walk up the chain and re-define the attribute methods
if they haven't been defined yet.
If the user defined a translation to a nested error on base we should
look it up in the same way we do for the other attributes.
If no translation is set, we fallback to the name of the association.
Fixes#48884.
`define_proxy_call` accepts `call_args` as an argument which impacts
method body generation but it doesn't use `call_args` in the `namespace`
generation which leads to the same cached method to be reused even if
`call_args` differ.
It has never been an issue since `define_proxy_call` was only used to
generate Active Record attribute methods and we were always passing
the same `call_args` per method name.
However, since https://github.com/rails/rails/pull/48533 we are using
`define_proxy_call` to generate alias attribute methods where `call_args`
differ for the same method name which leads to the same cached method
being reused in wrong places.
This commit fixes the issue by making sure `call_args` are being
considered when generating the `namespace` for the method.
When development tools try to load Rails components, they sometimes end up loading files that will error out since a dependency is missing. In these cases, the tooling can catch the error and change its behaviour.
However, since the warning is printed directly to `$stderr`, the tooling cannot catch and suppress it easily, which ends up causing noise in the output of the tool.
This change makes Rails print these warnings using `Kernel#warn` instead, which can be suppressed by the tooling.
This commit changes bodies of methods generated by `alias_attribute`
along with generating these methods lazily.
Previously the body of the `alias_attribute :new_title, :title` was
`def new_title; title; end`. This commit changes it to
`def new_title; attribute("title"); end`.
This allows for `alias_attribute` to be used to alias attributes named
with a reserved names like `id`:
```ruby
class Topic < ActiveRecord::Base
self.primary_key = :title
alias_attribute :id_value, :id
end
Topic.new.id_value # => 1
```
ActiveRecord::Base has a dedicated ActiveSupport load hook. This adds an
additional hook for ActiveModel::Model, so that when ActiveModel is
being used without ActiveRecord, it can still be modified.
Currently it is a bit unclear which dirty methods can be called on
Active Record models. You have to know that methods from ActiveModel::Dirty
are included.
It also unclear if methods can be invoked in the form of
`saved_change_to_name?` unless you read the documentation of the
`saved_change_to_attribute?` method.
By adding an introduction to the module we can show which methods are
defined specifically for Active Record, and how to call them, very
similar to the ActiveModel::Dirty introduction.
Linking to ActiveModel::Dirty makes it's also easier to find methods
defined there.
JSONGemEncoder.encode previously would always perform two passes. First
it would call `.as_json(options)`, but then would perform a second pass
"jsonify" to recursively call `.as_json` (this time without options)
until the data converges into a "JSON-ready" representation.
When options are not given, the second pass should be equivalent to the
first, so we can detect that, and only perform the "jsonify" step.
The only user-visible effect of this should be that we will pass no
options to `as_json` instead of an empty Hash, but implementations of
`as_json` should already be expected to accept that.
Active Model generates methods for each attribute to handle dirty
changes. As these methods are generated they can't be found when
searching for them in the API documentation.
We can use the `:method:` directive to document them in the form of
`*_will_change`, `*_previously_was`, etc.
This notation is already used for documenting ActiveModel::Dirty.
An alternative could be documenting the methods as:
`[attribute_name]_will_change`, `[attribute_name]_previously_was`, etc...
But that adds more noise to the method.
In #48106, `Module#deep_dup` was changed to return the module itself
(not a copy) when the module is not anonymous. However, that causes
non-anonymous modules to become frozen via `value.deep_dup.freeze` when
passed to `ActiveModel::Type::Helpers::Mutable#immutable_value`. So,
for example, class attributes can no longer be set on the module.
To prevent such issues, this commit removes the `freeze` from
`immutable_value`. `immutable_value` is only called by
`ActiveRecord::PredicateBuilder#build_bind_attribute`, which only cares
that other code cannot mutate the value, not that the value is actually
frozen.
This reverts commit 586436d370126322a1470c10c1fde73cf8dc8875, reversing
changes made to 866e053732636e64685a72e22d76e7988d06a000.
This is an unrevert of https://github.com/rails/rails/pull/46282. I
should have reverted the revert sooner but it kept falling off my radar.
Closes#46446