rails/activerecord/CHANGELOG.md

146 lines
4.4 KiB
Markdown
Raw Normal View History

* Use SQLite `IMMEDIATE` transactions when possible.
Transactions run against the SQLite3 adapter default to IMMEDIATE mode to improve concurrency support and avoid busy exceptions.
*Stephen Margheim*
* Raise specific exception when a connection is not defined.
The new `ConnectionNotDefined` exception provides connection name, shard and role accessors indicating the details of the connection that was requested.
*Hana Harencarova*, *Matthew Draper*
* Delete the deprecated constant `ActiveRecord::ImmutableRelation`.
*Xavier Noria*
* Fix duplicate callback execution when child autosaves parent with `has_one` and `belongs_to`.
Before, persisting a new child record with a new associated parent record would run `before_validation`,
`after_validation`, `before_save` and `after_save` callbacks twice.
Now, these callbacks are only executed once as expected.
*Joshua Young*
* `ActiveRecord::Encryption::Encryptor` now supports a `:compressor` option to customize the compression algorithm used.
```ruby
module ZstdCompressor
def self.deflate(data)
Zstd.compress(data)
end
def self.inflate(data)
Zstd.decompress(data)
end
end
class User
encrypts :name, compressor: ZstdCompressor
end
```
You disable compression by passing `compress: false`.
```ruby
class User
encrypts :name, compress: false
end
```
*heka1024*
* Add condensed `#inspect` for `ConnectionPool`, `AbstractAdapter`, and
`DatabaseConfig`.
*Hartley McGuire*
Add `.shard_keys` & `.connected_to_all_shards` Currently, there is no (simple) way to ask a model if it connects to a single database or to multiple shards. Furthermore, without looping through a model's connections, I don't believe there's an easy way to return a list of shards a model can connect to. This commit adds a `@shard_keys` ivar that's set whenever `.connects_to` is called. It sets the ivar to the result of `shards.keys`. `shards` in `.connects_to` defaults to an empty hash and therefore when calling `connects_to database: {...}` `@shard_keys` will be set to an empty array. `@shard_keys` is set _before_ the following lines: ``` if shards.empty? shards[:default] = database end ``` This conditional sets the one and only shard (`:default`) to the value of `database` that we pass to `.connects_to`. This allows for calling `connected_to(shard: :default)` on models configured to only connect to a database e.g.: ```ruby class UnshardedBase < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary } end class UnshardedModel < UnshardedBase end UnshardedBase.connected_to(shard: :default) { UnshardedBase.connection_pool.db_config.name } => primary ``` This is ultimately still an _unsharded_ model which is why `@shard_keys` gets set before the conditional. With the new `@shard_keys` ivar we need a way for descendants of the abstract AR model to return that same value. For that we leverage the existing `.connection_class_for_self` method. That method returns the ancestor of the model where `.connects_to` was called, or returns self if it's the connection class: ```ruby class UnshardedBase < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary } end class UnshardedModel < UnshardedBase end ActiveRecord::Base.connection_class_for_self => ActiveRecord::Base UnshardedBase.connection_class_for_self => UnshardedBase(abstract) UnshardedModel.connection_class_for_self => UnshardedBase(abstract) ``` The new `.shard_keys` method is a getter which returns the value of `@shard_keys` from the connection class or it returns an empty array. The empty array is necessary in cases where `connects_to` was never called. Finally, I've added an `.connected_to_all_shards` method which takes all of the arguments for `.connected_to` except for `shard`. Instead, it loops through every shard key and then delegates everything else to `.connected_to`. I've used `.map` instead of `.each` so that we can collect the results of each block.
2024-02-08 16:05:22 +08:00
* Add `.shard_keys`, `.sharded?`, & `.connected_to_all_shards` methods.
```ruby
class ShardedBase < ActiveRecord::Base
self.abstract_class = true
connects_to shards: {
shard_one: { writing: :shard_one },
shard_two: { writing: :shard_two }
}
end
class ShardedModel < ShardedBase
end
ShardedModel.shard_keys => [:shard_one, :shard_two]
ShardedModel.sharded? => true
ShardedBase.connected_to_all_shards { ShardedModel.current_shard } => [:shard_one, :shard_two]
```
*Nony Dutton*
* Add a `filter` option to `in_order_of` to prioritize certain values in the sorting without filtering the results
by these values.
*Igor Depolli*
* Fix an issue where the IDs reader method did not return expected results
for preloaded associations in models using composite primary keys.
*Jay Ang*
* Allow to configure `strict_loading_mode` globally or within a model.
Defaults to `:all`, can be changed to `:n_plus_one_only`.
*Garen Torikian*
* Add `ActiveRecord::Relation#readonly?`.
Reflects if the relation has been marked as readonly.
*Theodor Tonum*
* Improve `ActiveRecord::Store` to raise a descriptive exception if the column is not either
structured (e.g., PostgreSQL +hstore+/+json+, or MySQL +json+) or declared serializable via
`ActiveRecord.store`.
Previously, a `NoMethodError` would be raised when the accessor was read or written:
NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::Text
Now, a descriptive `ConfigurationError` is raised:
ActiveRecord::ConfigurationError: the column 'metadata' has not been configured as a store.
Please make sure the column is declared serializable via 'ActiveRecord.store' or, if your
database supports it, use a structured column type like hstore or json.
*Mike Dalessio*
* Fix inference of association model on nested models with the same demodularized name.
E.g. with the following setup:
```ruby
class Nested::Post < ApplicationRecord
has_one :post, through: :other
end
```
Before, `#post` would infer the model as `Nested::Post`, but now it correctly infers `Post`.
*Joshua Young*
* Add public method for checking if a table is ignored by the schema cache.
Previously, an application would need to reimplement `ignored_table?` from the schema cache class to check if a table was set to be ignored. This adds a public method to support this and updates the schema cache to use that directly.
```ruby
ActiveRecord.schema_cache_ignored_tables = ["developers"]
ActiveRecord.schema_cache_ignored_table?("developers")
=> true
```
*Eileen M. Uchitelle*
Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activerecord/CHANGELOG.md) for previous changes.