Active Record CHANGELOG(v7.1.0.rc2)
rails db:drop
実行時にSQLite3のshmファイルや-walファイルも削除するようになった。
Niklas Häusele
同CHANGELOGより
同一クラス内で、ある関連付けに対する#accepts_nested_attributes_for
が2回以上宣言された場合にArgumentError
を発生する変更(#49056)を取り消し。
ここで取り消された振る舞いは、#accepts_nested_attributes_for
がconcern内で定義され、そのconcernをinclude
しているクラス内でオーバーライドされる場合に壊れる。
Rafael Mendonça França
同CHANGELOGより
Active Record CHANGELOG(v7.1.0.rc1)
関連: Add support for unique constraints (PostgreSQL-only). by alpaca-tc · Pull Request #46192 · rails/rails
(PostgreSQL)unique制約のネーミングを改善。
*_unique_key
という命名だと、uniqueインデックスの短縮形と誤解される。
*_unique_constraint
という命名なら誤解されない。
Rails 7.1.0.beta1以前:
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_key :sections, name: "unique_section_position"
変更後:
add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_constraint :sections, name: "unique_section_position"
Ryuta Kamizono
同CHANGELOGより
MySQLを利用中、スキーマダンプ内のCHECK制約に含まれる一重引用符''
が重複する問題を修正。
CHECK制約に渡す式に引用符が既に含まれていると、mysql2アダプタのスキーマダンプが無効になっていた。
修正: #42424
Felix Tscheulin
同CHANGELOGより
SQLite3アダプタのコネクション設定のパフォーマンスを高速化。
Write-Ahead-Log(WAL)をsynchronous=NORMAL
モードで利用するようにし、ジャーナルサイズの上限(journal_size_limit
)、健全なサイズの共有メモリバッファ(mmap_size
)、共有キャッシュ(cache_size
)を設定したことで、Railsアプリケーションで平均して2倍改善された。
Stephen Margheim
同CHANGELOGより
参考: Enhancing your Rails app with SQLite | Fractaled Mind
SQLite3のbusy_handler
で、retries
をシンプルに上限回数まで行える設定を追加。
パフォーマンスが重要なアプリケーションでは、ビジーなコネクションを遅延なしで再試行するのが望ましい。database.yml
のretries
値(integer)で指定した回数に達するまで、busy_handler
関数でビジーコネクションへの再接続を(待ち時間を指数増加せずに)試行するようになった。
Stephen Margheim
同CHANGELOGより
SQLite3アダプタでsupports_insert_returning?
をサポート。
supports_insert_returning?
(AbstractAdapter
)を完全に実装することで、SQLite3アダプタでも自動生成カラム([#48241[#ar34])とカスタム主キーをサポートする。
Stephen Margheim
同CHANGELOGより
参考: Rails API ActiveRecord::ConnectionAdapters::AbstractAdapter
SQLite3アダプタで、結合演算子||
を含むデフォルト関数を処理できるようになった。
従来は、デフォルト関数で"'Ruby ' || 'on ' || 'Rails'"
のように静的な文字列が生成されていた。
改修によって、"Ruby on Rails"
を適切にアダプタに渡して利用できるようになった。
change_column_default "test_models", "ruby_on_rails", -> { "('Ruby ' || 'on ' || 'Rails')" }
Stephen Margheim
同CHANGELOGより
PostgreSQL固有のスキーマをschema.rbにダンプできるようにするcreate_schema
を追加。
Lachlan Sylvester
同CHANGELOGより
Active Record CHANGELOG(v7.1.0.beta1)
属性ごとに設定されるsupport_unencrypted_data
オプションを暗号化に追加。
特定の暗号化済み属性だけをsupport_unencrypted_data
で暗号化しないように設定可能になった。
このオプションは、ActiveRecord::Encryption.config.support_unencrypted_data == true
が設定済みの場合にのみ有効。
class User < ActiveRecord::Base
encrypts :name, deterministic: true, support_unencrypted_data: false
encrypts :email, deterministic: true
end
Alex Ghiculescu
同CHANGELOGより
参考: 週刊Railsウォッチ20230926: 暗号化属性の平文データサポートをsupport_unencrypted_data
オプションで属性ごとに無効化できるようになった
Active Recordのトランザクションでinstrumentation(計測)を利用可能になった。
トランザクションイベントをサブスクライブすることでトラッキングやinstrumentationで利用できるようになる。イベントペイロードには、コネクションの他にタイミングの詳細詳細情報も含まれる。
ActiveSupport::Notifications.subscribe("transaction.active_record") do |event|
puts "Transaction event occurred!"
connection = event.payload[:connection]
puts "Connection: #{connection.inspect}"
end
Daniel Colson, Ian Candy
同CHANGELOGより
参考: 週刊Railsウォッチ20230926: Active Recordのトランザクションをinstrumentationで計測できるようになった
参考: Active Support の Instrumentation 機能 - Railsガイド
マイグレーションヘルパーで複合主キーをサポート。
# "carts"テーブルの主キーが"(shop_id, user_id)"だとする
add_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id])
remove_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id])
foreign_key_exists?(:orders, :carts, primary_key: [:shop_id, :user_id])
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20230926: マイグレーションヘルパーで複合主キーをサポート
マイグレーションにCHECK制約を追加するときのif_not_exists
オプションをサポート。
add_check_constraint :posts, "post_type IN ('blog', 'comment', 'share')", if_not_exists: true
Cody Cutrer
同CHANGELOGより
参考: 週刊Railsウォッチ20230926: マイグレーションのadd_check_constraint
にif_not_exists
オプションを渡せるようになった
注: このプルリクはその後0f7fe4aで取り消されました。
同じクラス内の関連付けに対して#accepts_nested_attributes_for
が複数回宣言されるとArgumentError
を発生するようになった。
従来は、最後の宣言が以前の宣言をエラーなしでオーバーライドしていた。サブクラスでのオーバーライドは引き続き許可されている。
Joshua Young
同CHANGELOGより
Rails API: ActiveRecord::NestedAttributes(翻訳)
#merge
メソッドのrewhere
オプションを非推奨化。
#merge
メソッドのrewhere
オプションは置き換えなしに非推奨化され、Rails 7.2で削除される予定。
Adam Hess
同CHANGELOGより
参考: 週刊Railsウォッチ20230913: merge
にrewhere
オプションを渡すことが非推奨化された
unscope
が特定のケース(トリプルドット...
)で動作しない問題を修正。
修正前:
Post.where(id: 1...3).unscope(where: :id).to_sql # "SELECT `posts`.* FROM `posts` WHERE `posts`.`id` >= 1 AND `posts`.`id` < 3"
修正後:
Post.where(id: 1...3).unscope(where: :id).to_sql # "SELECT `posts`.* FROM `posts`"
修正:#48094
Kazuya Hatanaka
同CHANGELOGより
参考: 週刊Railsウォッチ20230913: where
でトリプルドット...
rangeを使うとunscope
が効かない問題を修正
has_secure_token
のデフォルトをon: :initialize
に変更。
新しいデフォルト値をon: :create
からon: :initialize
に変更した。
この設定はconfig.active_record.generate_secure_token_on
コンフィグで変更可能。
config.active_record.generate_secure_token_on = :create
Sean Doyle
同CHANGELOGより
参考: config.active_record.generate_secure_token_on
-- Rails アプリケーションを設定する - Railsガイド
7.0以降のマイグレーションとSQLiteを利用するとchange_column
でdatetime
カラムがprecision: 6
に設定されない問題を修正。
Hartley McGuire
同CHANGELOGより
to_key
で複合idをサポート。
#id
が既に配列の場合はto_key
で#id
値をArray
でラップしないようになる。
Nikita Vasilevsky
同CHANGELOGより
参考: Rails API to_key
-- ActiveModel::Conversion
参考: Rails API to_key
-- ActiveRecord::AttributeMethods::PrimaryKey
enum
にvalidate
オプションを追加。
class Contract < ApplicationRecord
enum :status, %w[in_progress completed], validate: true
end
Contract.new(status: "unknown").valid? # => false
Contract.new(status: nil).valid? # => false
Contract.new(status: "completed").valid? # => true
class Contract < ApplicationRecord
enum :status, %w[in_progress completed], validate: { allow_nil: true }
end
Contract.new(status: "unknown").valid? # => false
Contract.new(status: nil).valid? # => true
Contract.new(status: "completed").valid? # => true
Edem Topuzov, Ryuta Kamizono
同CHANGELOGより
参考: 週刊Railsウォッチ20230913: Active Recordのenumにエラーをraiseしないvalidate
オプションが追加された
in_batches
メソッドが、可能な場合に読み込み済みのリレーションを利用するようになった。
既に読み込まれているリレーションでバッチメソッドを呼び出すと、データベースからレコードを再度取得せずに読み込み済みのレコードを使うようになる。
Adam Hess
同CHANGELOGより
参考: Rails API in_batches
-- ActiveRecord::Batches
主キーが:id
でない場合にread_attribute(:id)
が主キーを返す振る舞いを非推奨化。
Rails 7.2以後は、read_attribute(:id)
はモデルの主キーに関係なくid
カラムの値を返すようになる。主キーの値を取得するには、代わりに#id
を使うこと。複合主キーモデルでは、read_attribute(:id)
は今後もid
カラムの値を返すようになる。
Adrianna Chang
同CHANGELOGより
参考: 週刊Railsウォッチ20230906: 主キーが:id
でない場合に主キーを返すread_attribute(:id)
を非推奨化
マイグレーション6.1のchange_table
が設定するdatetime
カラムの精度を修正。
Hartley McGuire
同CHANGELOGより
マイグレーション6.1のchange_column
が設定するdatetime
カラムの精度を修正。
Hartley McGuire
同CHANGELOGより
レコードのid
カラムの生の値にアクセスするActiveRecord::Base#id_value
を追加。
このエイリアスは、:id
カラムを宣言しているモデルに対してのみ提供される。
Adrianna Chang
同CHANGELOGより
参考: 週刊Railsウォッチ20230906: モデルのid
属性をid_value
で取得できるようになった
JSONで構造化されたデータ型を使うカラムにおけるActiveRecord::Store
の直前の変更トラッキングを修正。
従来は、JSONで構造化されたデータベース型を持っているカラムに対してストアがstore_accessor
として定義されていると、最後に保存したときの変更にアクセスする以下のメソッドが動作しなかった。
#saved_change_to_key?
#saved_change_to_key
#key_before_last_save
Robert DiMartino
同CHANGELOGより
PostgreSQL 15以降のインデックスでNULLS [NOT] DISTINCT
を完全サポート。
前回の作業でマイグレーションでのインデックス作成は行えるようになっていたが、schema.rbではサポートされていなかった。また、NULLS [NOT] DISTINCT
のマッチ順序が正しくなかったため、スキーマ検出が一定していなかった。
Gregory Jones
同CHANGELOGより
参考: 週刊Railsウォッチ20230823: PostgreSQL 15のNULLS NOT DISTINCT
をサポート
参考: PostgreSQL 15.4ドキュメント CREATE INDEX
名前付きバインド変数が使われている場合にsanitize_sql_*
メソッドでコロン:
をエスケープするようになった。
Justin Bull
同CHANGELOGより
参考: 週刊Railsウォッチ20230823: ActionRecord::Sanitization#replace_named_bind_variables
でコロン:をエスケープできるよう修正
#previously_new_record?
が削除済みレコードでtrue
を返す問題を修正。
従来は、レコードを作成してから削除すると#previously_new_record?
がtrue
を返すことがあった。
修正後は、レコードに対するどのUPDATEおよびDELETEでも変更を考慮することで#previously_new_record?
がfalse
を返すようになった。
Adrianna Chang
同CHANGELOGより
参考: この修正はRails 7.0.7でリリース済みです。
has_secure_token
にon:
でコールバックを指定できるようになった。
class User < ApplicationRecord
has_secure_token on: :initialize
end
User.new.token # => "abc123...."
Sean Doyle
同CHANGELOGより
訳注: デフォルトはon: create
です。
参考: 週刊Railsウォッチ20230809: has_secure_token
を生成するタイミングを指定可能になった
関連付けのカラムがオーバーラップしている場合のインメモリカウンタキャッシュの増加を修正。
2つの関連付けに名前の似ているカウンタキャッシュカラムがある場合、Active Recordが間違った方をインクリメントする可能性があった。
Jacopo Beschi, Jean Boussier
同CHANGELOGより
Active RecordのCipher::Aes256Gcm#inspect
でsecretsを表示しないようになった。
修正前:
ActiveRecord::Encryption::Cipher::Aes256Gcm.new(secret).inspect
"#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038 ... @secret=\"\\xAF\\bFh]LV}q\\nl\\xB2U\\xB3 ... >"
修正後:
ActiveRecord::Encryption::Cipher::Aes256Gcm(secret).inspect
"#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038>"
Petrik de Heus
同CHANGELOGより
参考: Rails API ActiveRecord::Encryption::Cipher::Aes256Gcm
トランザクションの振る舞いを非ローカルなreturn
、break
、throw
でコミットする以前の振る舞いに戻した。
Model.transaction do
model.save
return
other_model.save # 実行されなくなった
end
かつて、エラーが発生した場合にのみロールバックがトリガーされていた時代があったが、Ruby 2.3のtimeout
ライブラリが実行を中断するためにthrow
を使うようになり、オープン中のトランザクションがコミットされるという逆効果が生じていた。
これを解決するために、Active Record 6.1ではトランザクションを(コミットではなく)ロールバックするように動作を変更していた(不完全なトランザクションをコミットする可能性よりも安全性が高いため)。
Rails 6.1以降は、transaction
ブロック内でのreturn
やbreak
やthrow
の利用は根本的に非推奨となっていた。
しかし、timeout 0.4.0
のリリースにより、Timeout.timeout
で(throw
ではなく)再びエラーをraiseするようになった。これによって、Active Recordの振る舞いを当初の(驚きの少ない)動作に戻すことが可能になった。
Rails 6.1より前の「歴史的な」振る舞いは、以下の設定で有効にできる。
Rails.application.config.active_record.commit_transaction_on_non_local_return = true
また、Rails 7.1で作成する新規アプリケーションはデフォルトでこの振る舞いになる。
Jean Boussier
同CHANGELOGより
参考: Deprecate committing a transaction exited with return or throw by dylanahsmith · Pull Request #29333 · rails/rails
参考: config.active_record.commit_transaction_on_non_local_return
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20230809: トランザクションがreturn
、break
、throw
でコミットするようになった
#remove_connection
のname
引数を非推奨化。
#remove_connection
のname
引数は置き換えなしで非推奨化された。
#remove_connection
は、コネクションを確立するクラスで直接呼び出されるべき。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API remove_connection
-- ActiveRecord::ConnectionHandling
単数形の逆関連付けを経由するhas_one
through:
関連付けでレコードをビルド可能になった。
belongs_to
through:
関連付けでは、外部キーを主キーのモデルにリンクする必要はない。
has_one
の場合はこの関連付けがミュータブルではないため、レコードをビルドできなかった。
Gannon McGibbon
同CHANGELOGより
参考: 週刊Railsウォッチ20230802: belongs_to :inverse_of
を介したhas_one :through
関連付けで、レコードをビルドできるように修正
データベースでクエリログが有効な場合はプリペアドステートメントを無効にするようになった。
クエリログは毎回一意のクエリを作成するため、プリペアドステートメントとクエリログは互換性がない。
zzak, Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20230802: クエリログが有効な場合はプリペアドステートメントを無効にするよう修正
SHA1ハッシュダイジェストで非決定論的に暗号化された既存データの復号をサポート
これにより、Active Recordの新しい暗号化オプションが追加され、SHA1ハッシュダイジェストで非決定論的に暗号化されたデータを復号できるようになる。
Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true
新しいオプションは、7.0から7.1にアップグレードする際の問題に対処する。Active Record暗号化の初期化方法にバグがあったため、非決定論的暗号化に用いるキープロバイダは、RailsがRails.application.config.active_support.key_generator_hash_digest_class
でグローバルに設定したものではなく、SHA-1をダイジェストクラスとして利用していた。
Cadu Ribeiro and Jorge Manrubia
同CHANGELOGより
参考: config.active_record.support_sha1_for_non_deterministic_encryption
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20230725: SHA1ハッシュダイジェストで非決定論的に暗号化された従来のデータの復号をサポート
PostgreSQLのマイグレーションでenumのリネーム、値の追加、値のリネームが可能になった。
rename_enum
およびrename_enum_value
はリバース可能である。add_enum_value
はPostgreSQLの制約(enum値を削除できない)によりリバースできない。代替手段として、enum全体を削除してから再作成すること。
rename_enum :article_status, to: :article_state
add_enum_value :article_state, "archived" # will be at the end of existing values
add_enum_value :article_state, "in review", before: "published"
add_enum_value :article_state, "approved", after: "in review"
rename_enum_value :article_state, from: "archived", to: "deleted"
Ray Faddis
同CHANGELOGより
Rails: PostgreSQLアダプタでenumのリネーム、enum値の追加とリネームが可能になった(翻訳)
スキーマから複合主キーを導出可能になった。
複合主キーを含むスキーマを持つアプリケーションを起動したときにwarningが発生しないようになり、ActiveRecord::Base#primary_key
の値がnil
になることもなくなる。
以下のようなtravel_routes
テーブル定義とTravelRoute
モデルがあるとする。
create_table :travel_routes, primary_key: [:origin, :destination], force: true do |t|
t.string :origin
t.string :destination
end
class TravelRoute < ActiveRecord::Base; end
このTravelRoute.primary_key
の値は自動的に["origin", "destination"]
に導出される。
Nikita Vasilevsky
同CHANGELOGより
参考: 週刊Railsウォッチ20230628: スキーマから複合主キーを導出可能になった
connection_pool
にコネクションアダプタからraiseされる例外を保存するようになった。
例外を引き起こしたコネクションや、ロール、シャードなどのコンテキストがconnection_pool
に追加される。
Luan Vieira
同CHANGELOGより
参考: 週刊Railsウォッチ20230628: データベース関連の例外をconnection_pool
に保存するようになった
複合主キーを持つテーブルのfind_each
、find_in_batches
、in_batches
で:asc
、:desc
を指定可能になった。
複合主キーがあるテーブルでfind_each
、find_in_batches
、in_batches
を実行するときに、キーごとに:asc
や:desc
を指定可能になる。
Person.find_each(order: [:desc, :asc]) do |person|
person.party_all_night!
end
Takuya Kurimoto
同CHANGELOGより
参考: 週刊Railsウォッチ20230628: 複合主キーを持つテーブルのfind_each
、find_in_batches
、in_batches
で:asc
、:desc
を指定可能になった
has_one
/has_many
ポリモーフィックリレーションの関連付けにおけるwhere
の振る舞いを修正。
修正前:
Treasure.where(price_estimates: PriceEstimate.all)
#=> SELECT (...) WHERE "treasures"."id" IN (SELECT "price_estimates"."estimate_of_id" FROM "price_estimates")
修正後:
Treasure.where(price_estimates: PriceEstimate.all)
#=> SELECT (...) WHERE "treasures"."id" IN (SELECT "price_estimates"."estimate_of_id" FROM "price_estimates" WHERE "price_estimates"."estimate_of_type" = 'Treasure')
Lázaro Nixon
同CHANGELOGより
この修正は、Rails 7.0.6でリリース済みです。
Active Recordでのレコード作成時に自動生成カラムを割り当てられるようになる。
レコード作成ロジックを変更することで、auto_increment
カラムをレコード作成時に割り当て可能にする。これによって、モデルの主キーへのリレーションにかかわらず、レコード作成直後にauto_increment
カラムを割り当てられるようになる。
この変更によるメリットが最も大きいのはPostgreSQLアダプタで、RETURNING
ステートメントを利用するレコードのINSERT
後に、任意の個数の自動生成カラムをオブジェクトに割り当てられるようになる。
Nikita Vasilevsky
同CHANGELOGより
参考: 週刊Railsウォッチ20230621: オブジェクト作成時にデータベース側の自動入力属性を割り当て可能にする
connected_to
のshards
ハッシュの最初のキーをdefault_shard
で使うようになった。
アプリケーションによっては、コネクションモデルのシャード名に:default
を使いたくない場合がある。残念なことに、Active Recordはプールマネージャから正しいコネクションを得るために何らかのシャードを仮定しなければならないため、:default
シャードの存在を期待する。
アプリケーションで強制的に手動設定する代わりに、connects_to
がシャードのハッシュからデフォルトシャード名を推測して、最初のシャードをデフォルトであると仮定するようになる。
たとえば以下のようなモデルがあるとする。
class ShardRecord < ApplicationRecord
self.abstract_class = true
connects_to shards: {
shard_one: { writing: :shard_one },
shard_two: { writing: :shard_two }
}
これで、このクラスのdefault_shard
がshard_one
に設定されるようになる。
修正: #45390
Eileen M. Uchitelle
同CHANGELOGより
参考: 週刊Railsウォッチ20230621: connected_to
のshards
ハッシュの最初のキーをdefault_shard
で使うようになった
背後のカラムがバイナリエンコードになっているシリアライズ属性での変更検出を修正。
Jean Boussier
同CHANGELOGより
この修正は、Rails 7.0.5でリリース済みです。
参考: 週刊Railsウォッチ20230613: change_in_place?
の挙動を修正
全コネクションプールにある全コネクションを即座にクローズするActiveRecord.disconnect_all!
を追加。
Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20230613: マルチプルDBで使えるActiveRecord.disconnect_all!
が追加
トランザクションに残っているコネクションを破棄する機能を改善。
エラーが原因で、within_new_transaction
のコネクションがオープン中のトランザクションに予期せず残ってしまうことがある。そうなるとコネクションが再利用されてしまい、以下のようなエラーが発生する可能性がある。
- 書き込みが実際は成功しているにもかかわらず失敗したように見える
- 書き込みが実際は失敗しているにもかかわらず成功したように見える
- 読み込んだデータが古い、またはコミットされていない
従来は以下のケースについては検出されていた。
- トランザクション内でエラーが発生し、ロールバックを試行中に別のエラーが発生した場合
改修によって、以下のケースも検出されるようになった。
- トランザクションの開始直後にエラーが発生した場合
- トランザクションのコミット中にエラーが発生し、ロールバックを試行中に別のエラーが発生した場合
- トランザクションのロールバック中にエラーが発生した場合
Nick Dower
同CHANGELOGより
Active Recordのクエリキャッシュが直近で最も利用頻度の低い(LRU: least recently used)エントリーを削除するようになった。
デフォルトでは、最も直近で利用された100
件のクエリのみを維持する。
このキャッシュサイズはdatabase.yml
で変更可能。
development:
adapter: mysql2
query_cache: 200
クエリキャッシュそのものを無効にすることも可能。
development:
adapter: mysql2
query_cache: false
Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20230607: 保持するクエリキャッシュを直近50件までに変更した
check_pending!
を非推奨化。今後はcheck_all_pending!
を使うこと。
check_pending!
が保留中のマイグレーションをチェックする対象は、現在の(または渡された)データベースコネクションのみでマルチプルデータベースに対応していない。このcheck_pending!
は非推奨化される。今後は、指定の環境にある複数のデータベース設定ですべての保留中マイグレーションをチェックするcheck_all_pending!
を使うこと。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API check_all_pending!
-- ActiveRecord::Migration
increment_counter
やdecrement_counter
にby:
オプションで増分値を渡せるようになった。
Post.increment_counter(:comments_count, 5, by: 3)
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20230607: Active Recordのカウンタインクリメントやデクリメントに1以外の増分量を効果的に指定できるようになった
Array#intersect?
をActiveRecord::Relation
に追加。
Array#intersect?
はRuby 3.1以降でのみ利用可能。
これにより、ActiveRecord::Relation
でRuboCopのStyle/ArrayIntersect
copを利用できるようになる。
John Harry Kelly
同CHANGELOGより
参考: 週刊Railsウォッチ20230524: ActiveRecord::Relation
にintersects?
が追加された
マイグレーションでdeferrable
オプション(先延ばし可能)を有効にした外部キーをt.references
に渡せるよう修正。
Hiroyuki Ishii
同CHANGELOGより
参考: 週刊Railsウォッチ20230524: マイグレーションでreferences
にdeferrable
オプション付きの外部キーを渡しても無視される問題を修正
関連: #46192
add_foreign_key
のdeferrable: true
オプションを非推奨化。
非推奨化されたdeferrable: true
オプションはRails 7.2で削除される予定。今後はdeferrable: :immediate
が推奨される。
非推奨化の理由は、deferrable: true
とdeferrable: :deferred
の意味がわかりにくいため(どちらの値もtruthyに見えてしまう)。
推奨されるdeferrable: :immediate
の振る舞いは、#46192で追加されたadd_unique_key
のdeferrable
オプションと同じ。
Hiroyuki Ishii
同CHANGELOGより
参考: 週刊Railsウォッチ20230524: add_foreign_keyのdeferrable: trueオプションを非推奨化する
関連: Active Record: clear query cache automatically when calling #execute
by casperisfine · Pull Request #48061 · rails/rails
AbstractAdapter
の#execute
と#exec_query
でクエリキャッシュをクリアするよう修正。
リードオンリーのSQLクエリをクエリキャッシュをクリアせずに実行する必要がある場合は、AbstractAdapter#select_all
を使うこと。
Jean Boussier
同CHANGELOGより
参考: Rails API select_all
-- ActiveRecord::ConnectionAdapters::DatabaseStatements
関連: Common Table Expression support added "out-of-the-box" by vlado · Pull Request #37944 · rails/rails
.joins
や.left_outer_joins
もCTE(Common Table Expression)で使えるようになった。
例:
Post
.with(commented_posts: Comment.select(:post_id).distinct)
.joins(:commented_posts)
#=> WITH (...) SELECT ... INNER JOIN commented_posts on posts.id = commented_posts.post_id
Vladimir Dementyev
同CHANGELOGより
参考: §Common Table Expression -- Hierarchical and recursive queries in SQL - Wikipedia
参考: 週刊Railsウォッチ20230524: joins
でCTEをサポート
ActiveRecord::ConnectionAdapters::Mysql2Adapter
(名前はactive_record_mysql2adapter
)にloadフックを追加。これにより、ActiveRecord::ConnectionAdapters::Mysql2Adapter
の一部をオーバーライド可能になり、既にloadフックを備えているPostgreSQLAdapter
やSQLite3Adapter
と統一される。
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20230524: Mysql2Adapter
にloadフックを追加
Trilogyデータベースクライアント用のアダプタを導入。
TrilogyはMySQL互換のデータベースクライアント。Railsアプリケーションのconfig/database.yml
ファイルを以下のように設定することでTrilogyを利用できる。
development:
adapter: trilogy
database: blog_development
pool: 5
または、以下のようにDATABASE_URL
環境変数による設定でも利用できる。
ENV['DATABASE_URL'] # => "trilogy://localhost/blog_development?pool=5"
Adrianna Chang
同CHANGELOGより
![trilogy-libraries/trilogy - GitHub]()
![trilogy-libraries/activerecord-trilogy-adapter - GitHub]()
参考: 週刊Railsウォッチ20230502: Trilogyデータベースクライアント用のアダプタが導入される
モデルで定義されているafter_commit
コールバックが、定義順に正しく実行されるようになった。
class User < ActiveRecord::Base
after_commit { puts("これが最初に呼ばれる") }
after_commit { puts("これが次に呼ばれる") }
end
従来のコールバックは逆順で実行されていた。以下のコンフィグで新しい振る舞いを有効にできる。
config.active_record.run_after_transaction_callbacks_in_order_defined = true
新規アプリでは、これがデフォルトの振る舞いになる。
Alex Ghiculescu
同CHANGELOGより
参考: config.active_record.run_after_transaction_callbacks_in_order_defined
-- Rails アプリケーションを設定する - Railsガイド
has_one
関連付けやhas_many
関連付けでinverse_of
が指定されている場合にforeign_key
を推論するようになった。
has_many :citations, foreign_key: "book1_id", inverse_of: :book
上を以下のようにシンプルに書けるようになる。
has_many :citations, inverse_of: :book
foreign_key
は、対応するbelongs_to
関連付けから読み取られる。
Daniel Whitney
同CHANGELOGより
参考: 週刊Railsウォッチ20230412: has_one
やhas_many
にinverse_of
が存在する場合にfoerign_key
を推論するようになった
自動生成されるインデックス名の長さに上限が設定されるようになった。
自動生成されるインデックス名は最大62バイトになった。この長さは、MySQL、PostgreSQL、SQLite3のインデックス名のデフォルトの最大長さに収まる。
インデックス名がこの上限を超えた場合は自動的に短縮される。
変更前(長すぎる):
index_testings_on_foo_and_bar_and_first_name_and_last_name_and_administrator
変更後(短縮形):
idx_on_foo_bar_first_name_last_name_administrator_5939248142
短縮形には、インデックス名がデータベースで一意になるようハッシュが追加される。
Mike Coutermarsh
同CHANGELOGより
参考: 週刊Railsウォッチ20230425: 自動生成されるインデックス名を上限で切り詰めるようになった
安定性が高く最適化されたMarshalシリアライザがActive Recordモデルに導入された。
以下のコンフィグで有効になる。
config.active_record.marshalling_format_version = 7.1
Jean Boussier
同CHANGELOGより
参考: config.active_record.marshalling_format_version
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20230412: ActiveRecord::Base
にmarshal_dump
とmarshal_load
を実装
複合主キー向けの"タプル"構文をwhere
に導入。
where
を用いるクエリで新しいタプル(tuple)構文が使えるようになった。これは、キーに「カラムの配列」、値に「それに対応するタプルの配列」をそれぞれ渡せる。
このキーではカラムのリストを指定するが、値はそのカラムリストに適合する順序付きタプルの配列となる。
例:
# Cpk::Book => Cpk::Book(author_id: integer, number: integer, title: string, revision: integer)
# Cpk::Book.primary_key => ["author_id", "number"]
book = Cpk::Book.create!(author_id: 1, number: 1)
Cpk::Book.where(Cpk::Book.primary_key => [[1, 2]]) # => [book]
# Topic => Topic(id: integer, title: string, author_name: string...)
Topic.where([:title, :author_name] => [["The Alchemist", "Paul Coelho"], ["Harry Potter", "J.K Rowling"]])
Paarth Madan
同CHANGELOGより
参考: 週刊Railsウォッチ20230412: 複合主キー向けの"タプル"構文をwhere
に導入
SQL警告メッセージをエラーコードでフィルタできるようになった。
以下のActive Recordコンフィグで特定の警告コードを無視できる。
# 常に無視すべき警告の許可リストを設定する
config.active_record.db_warnings_ignore = [
"1062", # MySQL Error 1062: Duplicate entry
]
この機能はMySQLアダプタとPostgreSQLアダプタでサポートされる。
Nick Borromeo
同CHANGELOGより
参考: 週刊Railsウォッチ20230412: SQL警告メッセージをエラーコードでフィルタできるようになった
:active_record_fixtures
遅延読み込みフックを導入。
この名前で定義したフックは、クラスにTestFixtures
がinclude
されると常に実行されるようになる。
ActiveSupport.on_load(:active_record_fixtures) do
self.fixture_paths << "test/fixtures"
end
klass = Class.new
klass.include(ActiveRecord::TestFixtures)
klass.fixture_paths # => ["test/fixtures"]
Andrew Novoselac
同CHANGELOGより
参考: 週刊Railsウォッチ20230412: TestFixtures
をinclude
するたびにloadフックを実行するように修正
TestFixtures
に#fixture_paths
(複数形)を追加。
#fixture_paths
アクセサを使うことで、複数のフィクスチャパスを指定できるようになった。
アプリは引き続きデフォルトでtest/fixtures
を単一のフィクスチャパスとして持つが、追加のフィクスチャパスも指定できるようになる。
ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures"
ActiveSupport::TestCase.fixture_paths << "component2/test/fixtures"
TestFixtures#fixture_path
(単数形)は非推奨化された。
Andrew Novoselac
同CHANGELOGより
参考: 週刊Railsウォッチ20230405: fixtureパスをRailsエンジン単位で指定可能になった
PostgreSQLのEXCLUDE
制約でDEFERRABLE
をサポート。
デフォルトでは、PostgreSQLのEXCLUDE
制約は個別のステートメントの後でチェックされる。
ほとんどのユースケースではこれで上手くいくが、以下のように範囲がオーバーラップする複数のステートメントを用いてレコードを置き換える場合は大きな制限となる。
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :immediate
deferrable: :immediate
を指定すると、制約が個別のステートメントの後でチェックされる。
しかしトランザクション内でSET CONSTRAINTS ALL DEFERRED
を用いてチェックを手動で延期すれば、トランザクション終了後にEXCLUDE
制約をチェックするようになる。
これと同じことを、以下のようにデフォルトの振る舞いをimmediate
チェック(=個別のステートメントの後でチェックする)からdeferred
チェック(=トランザクション終了後にチェックする)に変更することでも可能になった。
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :deferred
Hiroyuki Ishii
同CHANGELOGより
参考: PostgreSQL 15ドキュメント SET CONSTRAINTS
delegated_type
にforeign_type
オプションを渡すことで{role}_class
メソッドに反映されるようになった。
foreign_type
オプションを渡すことで、delegated_type
で標準でない{role}_type
カラム名を利用できるようになった。
このオプションは、delegated_type
がラップしている背後のbelongs_to
関連付けへforwardされるforeign_type
と同じ。
Jason Karns
同CHANGELOGより
参考: 週刊Railsウォッチ20230405: Delegated Typesでカスタムカラム名を指定するforeign_type
オプションが追加された
Rails: ActiveRecord::DelegatedType APIドキュメント(翻訳)
関連: Adds support USING INDEX
for unique constraints in PostgreSQL. by alpaca-tc · Pull Request #47971 · rails/rails
関連: Deprecate deferrable: true
option of add_foreign_key
by alpaca-tc · Pull Request #47659 · rails/rails
UNIQUE制約のサポートを追加(PostgreSQLのみ)。
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_key :sections, name: "unique_section_position"
UNIQUE制約に関しては、PostgreSQLのUNIQUE制約のドキュメントを参照。
デフォルトでは、PostgreSQLでのユニーク制約は個別のステートメントの後にチェックされる。
ほとんどの場合はこれで問題ないが、複数のステートメントを利用してレコードのuniqueカラムを置換する場合には大きな成約となる。
以下の例では、レコード間でuniqueカラムを交換している。
# このpositionはuniqueカラム
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
デフォルトの振る舞いでは、最初のUPDATE
ステートメントを実行する時点で失敗する。
マイグレーションで以下のようにadd_unique_key
に:deferrable
オプションを渡すことで、このチェックを先延ばしできるようになった。
add_unique_key :items, [:position], deferrable: :immediate
deferrable: :immediate
を指定しても、振る舞いは最初の例と変わらないが、トランザクション内で SET CONSTRAINTS ALL DEFERRED
を使ってこのチェックを手動で先延ばしできるようになる。
これにより、UNIQUE制約がトランザクションの完了後にチェックされるようになる。
また、以下のようにdeferrable: :deferred
を指定することで、個別のステートメント後にチェックするデフォルトの振る舞いを、トランザクション完了後にチェックする先延ばしチェックに変更することも可能。
add_unique_key :items, [:position], deferrable: :deferred
既存のuniqueインデックスを先延ばし可能にしたい場合は、以下のように:using_index
オプションを渡すことで先延ばし可能なUNIQUE制約を作成できる。
add_unique_key :items, deferrable: :deferred, using_index: "index_items_on_position"
Hiroyuki Ishii
同CHANGELOGより
参考: 週刊Railsウォッチ20230502: PostgreSQL: UNIQUE制約でUSING INDEXをサポート
関連: Remove deprecated methods in ``Tasks::DatabaseTasks` · rails/rails@71f61b1
非推奨化されていたTasks::DatabaseTasks.schema_file_type
を削除。
Rafael Mendonça França
同CHANGELOGより
関連: Deprecate partial_writes
in favor of partial_inserts
and partial_updates
by casperisfine · Pull Request #42355 · rails/rails
非推奨化されていたconfig.active_record.partial_writes
を削除。
Rafael Mendonça França
同CHANGELOGより
関連: Define deprecated delegators for the cattr that were moved out of AR::Base by casperisfine · Pull Request #42489 · rails/rails
非推奨化されていたActiveRecord::Base
コンフィグのアクセサメソッドを削除。
Rafael Mendonça França
同CHANGELOGより
configs_for
から:include_replicas
引数を削除。今後は:include_hidden
を使うこと。
Eileen M. Uchitelle
同CHANGELOGより
アプリケーションのコンフィグをカスタムのハッシュキーで検索できるようになった。
カスタム設定を登録した場合や、ハッシュが特定のキーとマッチする設定を見つけたい場合は、configs_for
にconfig_key
オプションを渡せるようになった。
たとえば、キーがvitess
のdb_config
がある場合、そのキーにマッチするデータベース設定のハッシュを以下のように検索できる。
ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary", config_key: :vitess)
ActiveRecord::Base.configurations.configs_for(env_name: "development", config_key: :vitess)
Eileen M. Uchitelle
同CHANGELOGより
参考: 週刊Railsウォッチ20230322: データベース設定のカスタムハンドラを登録可能になった
アプリケーションでカスタムのデータベース設定ハンドラを登録できるようになった。
データベース設定がカスタムメソッドに応答するようにカスタマイズしたい場合に、カスタムハンドラを登録する仕組みを追加する。これは、Rails以外のデータベースアダプタやVitessなどのツールで、標準のHashConfig
やUrlConfig
とは異なる方法で設定したい場合に有用。
以下のデータベースYAMLで、primary
データベースを UrlConfig
にしたまま、animals
dbでCustomConfig
オブジェクトを作成したいとする。
development:
primary:
url: postgres://localhost/primary
animals:
url: postgres://localhost/animals
custom_config:
sharded: 1
カスタムハンドラを登録するには、最初にカスタムメソッドを持つクラスを作成する。
class CustomConfig < ActiveRecord::DatabaseConfigurations::UrlConfig
def sharded?
custom_config.fetch("sharded", false)
end
private
def custom_config
configuration_hash.fetch(:custom_config)
end
end
次にこのコンフィグをイニシャライザで登録する。
ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|
next unless config.key?(:custom_config)
CustomConfig.new(env_name, name, url, config)
end
これで、アプリケーションが起動すると、:custom_config
キーの設定ハッシュがCustomConfig
オブジェクトになり、sharded?
に応答するようになる。アプリケーションは、Active Recordでこのカスタムハンドラが利用されるように条件を処理する必要がある。
Eileen M. Uchitelle and John Crepezzi
同CHANGELOGより
参考: 週刊Railsウォッチ20230322: データベース設定のカスタムハンドラを登録可能になった
ActiveRecord::Base.serialize
のデフォルトがYAMLでなくなった。
YAMLのパフォーマンスは高くないうえに、注意しないとセキュリティ上の問題を引き起こす可能性がある。
残念ながら、Rubyの標準ライブラリには置き換えに適したシリアライザがない。
明らかな選択肢としてはJSONがあり、このユースケースには適したフォーマットだが、Ruby標準ライブラリのJSONシリアライザは厳密性が十分ではない(未知の型を文字列にキャストする形でフォールバックするため、データが破損する可能性がある)。
Oj
などのサードパーティJSONライブラリは、これに適したstrictモードを備えている。
ユーザーは、自分たちの制約に基づいてシリアライザを選択することが望ましい。
従来のデフォルト設定に戻したい場合は、以下を設定する。
config.active_record.default_column_serializer = YAML
Jean Boussier
同CHANGELOGより
参考: config.active_record.default_column_serializer
-- Rails アプリケーションを設定する - Railsガイド
![ohler55/oj - GitHub]()
ActiveRecord::Base.serialize
のシグネチャが変更された。
serialize
に、2個の可能な値を渡せる単一の第2位置引数ではなく、2種類のキーワード引数(coder
とtype
)を渡せるように変更された。
変更前:
serialize :content, JSON
serialize :backtrace, Array
変更後:
serialize :content, coder: JSON
serialize :backtrace, type: Array
Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20230314: デフォルトのカラムシリアライザを定義可能になった
YAMLカラムで可能な場合はYAML.safe_dump
を使うようになった。
psych 4.0.1
以降、YAML.safe_load
と同様の型制約を利用可能で、使いやすいYAML.safe_dump
を適用可能になった。
最初にシリアライズするときは、許可された型だけをペイロードで使うことが望ましい。そうしないと、データベース内に無効なレコードが残る可能性がある。
Jean Boussier
同CHANGELOGより
![ruby/psych - GitHub]()
ActiveRecord::QueryLogs
における壊れたエンコーディングの処理を改善。
BLOBフィールドを含むクエリをビルドするときにバイナリデータが含まれることがよくある。文字列がASCII-8BITで慎重にエンコードされない限り、通常はUTF-8
でエンコードされてQueryLogs
が失敗する可能性があった。
この修正により、ActiveRecord::QueryLogs
はクエリの正しいエンコードに依存しなくなった。
Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20230221: クエリのエンコードが壊れている場合のActiveRecord::QueryLogs
の処理を改善
create_table_migration
テンプレートのオーバーライドがActiveRecord::Generators::ModelGenerator
で反映されないバグを修正。
rails g model create_books title:string content:text
修正により、上のジェネレータが以下の場所からこの順序でcreate_table_migration.rb.tt
テンプレートを読み込むようになった。
lib/templates/active_record/model/create_table_migration.rb
lib/templates/active_record/migration/create_table_migration.rb
Spencer Neste
同CHANGELOGより
参考: 週刊Railsウォッチ20230613: モデルのジェネレータにcreate_table_migration
テンプレートのオーバーライドが正しく反映されない問題を修正
ActiveRecord::Relation
の#explain
にオプションを渡せるようになった。
explain
に:analyze
オプションやverbose
オプションを渡すことで、クエリプラン分析を詳細に行えるようになった。現在サポートされているデータベースおよびアダプタはPostgreSQLとMySQL。
Customer.where(id: 1).joins(:orders).explain(:analyze, :verbose)
Reid Lynch
同CHANGELOGより
参考: 週刊Railsウォッチ20230214: ActiveRecord::Relation#explain
にオプションを渡せるようになった
複数のArel::Nodes::SqlLiteral
ノードを互いに追加してArel::Nodes::Fragments
ノードを形成できるようになった。これにより、多くのSQLスニペットを結合できるようになる。
Matthew Draper, Ole Friis
同CHANGELOGより
新規レコードでActiveRecord::Base
の#signed_id
が呼び出されたらエラーを発生するようになった。
従来はid = nil
を元にしていたため、利用できないIDを返すことがあった。
Alex Ghiculescu
同CHANGELOGより
SQLのwarningを通知できるようにした。
以下のActive Recordコンフィグを設定することで、SQL warningの通知が有効になる。
# SQLクエリでwarningが発生した場合の操作を設定する
config.active_record.db_warnings_action = :raise
# warningの許可リストを設定する(設定したwarningは常に無視される)
config.active_record.db_warnings_ignore = [
/Invalid utf8mb4 character string/,
"An exact warning message",
]
この機能はMySQLアダプタとPostgreSQLアダプタでサポートされる。
Adrianna Chang, Paarth Madan
同CHANGELOGより
参考: config.active_record.db_warnings_action
-- Rails アプリケーションを設定する - Railsガイド
参考: config.active_record.db_warnings_ignore
-- Rails アプリケーションを設定する - Railsガイド
#regroup
クエリメソッドを追加。これは.unscope(:group).group(fields)
のショートハンド。
例:
Post.group(:title).regroup(:author)
# SELECT `posts`.`*` FROM `posts` GROUP BY `posts`.`author`
Danielius Visockas
同CHANGELOGより
参考: 週刊Railsウォッチ20230207: Active Recordにregroup
メソッドとregroup!
メソッドが追加された
PostgreSQLアダプタのenable_extension
メソッドで、他のスキーマによってインストールされていなければならないPostgreSQL拡張をスキーマ名.拡張名
形式で指定できるようになった。
例: enable_extension('heroku_ext.hstore')
Leonardo Luarte
同CHANGELOGより
マイグレーションのadd_index
に:include
オプションを追加(PostgreSQLのみ)。
PostgreSQLのINCLUDE
(キーでないカラムをインデックスに含める)のサポートを追加。
add_index(:users, :email, include: [:id, :created_at])
上は以下を生成する。
CREATE INDEX index_users_on_email USING btree (email) INCLUDE (id, created_at)
Steve Abrams
同CHANGELOGより
参考: 週刊Railsウォッチ20230328: PostgreSQLのadd_index
でinclude
とwhere
を両方使えるようにする
ActiveRecord::Relation
’の以下のメソッドに、同等のEnumerable
により近い形でマッチするパターン引数をオプションで渡せるようになった。
George Claghorn
同CHANGELOGより
# 以下の2つは同等
products.any?(MediaBlock)
products.any? { |product| MediaBlock === product }
参考: 週刊Railsウォッチ20230125: ActiveRecord::Relation
の#none?
、#any?
、#one?
でEnumerable
と同様のパターン引数を渡せるようになった
属性の正規化を宣言するActiveRecord::Base.normalizes
を追加。
属性の正規化は、属性の代入または更新時に適用され、正規化された値はデータベースに永続化される。また、この正規化はクエリメソッドの対応するキーワード引数にも適用されるので、正規化されていない値でレコードをクエリできるようになる。
例:
class User < ActiveRecord::Base
normalizes :email, with: -> email { email.strip.downcase }
normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") }
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.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count # => 1
User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0
User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") # => true
User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
Jonathan Hefner
同CHANGELOGより
Rails 7.1: ActiveRecord::Baseにnormalizesが追加された(翻訳)
before_committed!
コールバックの振る舞いの変更をコンフィグで戻せるようになった。
#46525でbefore_committed!
コールバックの動作が変更され、トランザクションに登録されたすべてのレコードでコールバックが実行されるようになった。この振る舞いを、config.active_record.before_committed_on_all_records
という設定オプションで制御できるようになった(Rails 7.1ではデフォルトで有効)。
Adrianna Chang
同CHANGELOGより
参考: 週刊Railsウォッチ20221206: before_committed!
コールバックをレコードの直近のコピーに対して実行するよう修正
参考: config.active_record.before_committed_on_all_records
-- Rails アプリケーションを設定する - Railsガイド
クエリログのnamespaced_controller
タグがコントローラの名前空間フォーマットとマッチするよう修正。
たとえばNameSpaced::UsersController
で処理されたリクエストは以下のようにログ出力されるようになった。
:controller # "users"
:namespaced_controller # "name_spaced/users"
Alex Ghiculescu
同CHANGELOGより
参考: Rails API ActiveRecord::QueryLogs
参考: config.active_record.query_log_tags
-- Rails アプリケーションを設定する - Railsガイド
ActiveRecord::Calculations
の#ids
が一意のidリストだけを返すよう修正。
ActiveRecord::Calculations#ids
が更新され、eager_load
、preload
、includes
でベースモデルの一意のidリストだけを返すようになった。
Post.find_by(id: 1).comments.count
# => 5
Post.includes(:comments).where(id: 1).pluck(:id)
# => [1, 1, 1, 1, 1]
Post.includes(:comments).where(id: 1).ids
# => [1]
Joshua Young
同CHANGELOGより
参考: 週刊Railsウォッチ20221220: ActiveRecord::Calculations#ids
が返すidが重複する問題を修正
PostgreSQLのcitext
カラムでは大文字小文字を区別しないクエリにlower()
を追加しないよう修正。
従来はuniquenessバリデーションなどでcase_sensitive: false
を指定したときのクエリにlower()
が追加されていた。
しかし、lower()
が定義されていないインデックスに対してこれを行うとインデックスが効かなくなることが見落とされていた。
Phil Pirozhkov
同CHANGELOGより
参考: PostgreSQL 15ドキュメント 9.4. 文字列関数と演算子
参考: PostgreSQL 15ドキュメント F.10. citext
参考: 週刊Railsウォッチ20221213: PostgreSQLのcitext
型カラムの検索時にlower()
を使わないようにした
AbstractMysqlAdapter
の#sync_timezone_changes
メソッドをMySQL::DatabaseStatements
に移動した。
これにより、サブクラスで#raw_execute
をオーバーライドせずにデータベースのタイムゾーン変更を同期できるようになった。
Adrianna Chang, Paarth Madan
同CHANGELOGより
マイグレーションのSQLダンプでバージョン番号に余分な行が追加されていたのを修正。
この変更によってinsert_versions_sql
関数が修正され、現在のマイグレーションバージョン番号を含む挿入文字列の末尾に余分な改行文字が2つ含まれないようになる。
Misha Schwartz
同CHANGELOGより
composed_of
の値のfreeze
やdup
を修正。
従来のコンポジション値は、混乱を招く2通りの振る舞いを示していた。
- コンポジション値を読み取るときは値が
freeze
されない。このため、背後のデータベースカラムとの同期がずれてしまう。
- コンポジション値を書き込むときは引数が
freeze
される。これによって呼び出し側が混乱する可能性がある。
修正後、データベースカラムに基づいてインスタンス化されたコンポジション値はfreeze
されるようになった(問題1の修正)。代入したコンポジション値はdup
されるようになり、dup
したものをfreeze
するようになった(問題2の修正)。
Greg Navis
同CHANGELOGより
参考: Rails API ActiveRecord::Aggregations::ClassMethods
大文字小文字を区別しないカラムでキャッシュが効かなかったのを修正。
カラムが大文字小文字を区別しない比較が可能かどうかをチェックすることで余分なクエリを発行しないよう修正した。
Phil Pirozhkov
同CHANGELOGより
ActiveRecord.enum
によるメソッド生成をinstance_methods: false
オプションで無効にできるようになった。
Alfred Dominic
同CHANGELOGより
参考: Rails 7.1に入る主要な機能まとめ(3) -- ActiveRecord#enum
のメソッド生成を無効にするオプションが追加された
belongs_to
関連付けで変更が生じていない場合のバリデーションを回避するようになった。
従来のActive Recordは、レコード更新時にbelongs_to
関連付けで(存在が必須と設定されている場合に)存在チェックの追加クエリを実行していたが、属性が変更されていない場合でも実行していた。
修正後は、belongs_to
に関連するカラムだけが存在チェックされるようになった。ただしこの方法では孤立レコードができてしまう可能性があるので、この問題を回避するには外部キーを使う必要がある。
この振る舞いは、以下のコンフィグで制御できる。
config.active_record.belongs_to_required_validates_foreign_key = false
この設定はconfig.load_defaults 7.1
ではデフォルトでfalse
に設定される。
fatkodima
同CHANGELOGより
参考: config.active_record.belongs_to_required_validates_foreign_key
-- Rails アプリケーションを設定する - Railsガイド
参考: Rails 7.1に入る主要な機能まとめ(3) -- 属性が変更されていないbelongs_to
関連付けのバリデーションを回避するようになった
has_one
関連付けとbelongs_to
関連付けで、オーナーモデルにreset_関連付け名
が定義されるようになった。
このメソッドは、キャッシュされた関連付けレコードがあればアンロードし、次回のアクセスでデータベースから読み込むようになる。
George Claghorn
同CHANGELOGより
参考: Rails 7.1に入る主要な機能まとめ(3) -- 単数形の関連付けをリセットできるようになった
serialize
にyaml
オプションが追加され、permitted_classes
(safe_load
用)やunsafe_load
を属性単位で設定できるようになった。
Carlos Palhares
同CHANGELOGより
# 同APIドキュメントより
class User < ActiveRecord::Base
serialize :preferences, yaml: { permitted_classes: [Symbol, Time] }
end
永続化を行うbuild
メソッドを追加。
new
のラッパーを提供し、関連付けのbuild
メソッドと同じ記法で、create
と同様にハッシュの配列から複数のレコードを作成する機能を提供する。
Sean Denny
同CHANGELOGより
# 同APIドキュメントより
# 単一のオブジェクトをビルド
User.build(first_name: 'Jamie')
# 新規オブジェクトの配列を渡してビルド
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
# 単一のオブジェクトをビルドし、ブロックで他の属性を設定
User.build(first_name: 'Jamie') do |u|
u.is_admin = false
end
# 新規オブジェクトの配列を渡してビルド:(ブロックはオブジェクトごとに設定される)
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
u.is_admin = false
end
参考: 週刊Railsウォッチ20221206: build
メソッドにハッシュの配列を渡すことで複数のオブジェクトをまとめてbuild
できるようになった
attr_readonly
で生成した属性に代入するとエラーを発生するようになった。
class Post < ActiveRecord::Base
attr_readonly :content
end
Post.create!(content: "cannot be updated")
post.content # "cannot be updated"
post.content = "something else" # => ActiveRecord::ReadonlyAttributeError
従来はデータベースに書き込まずに代入に成功してしまい、エラーを発生しなかった。
この振る舞いは以下のコンフィグで制御できる。
config.active_record.raise_on_assign_to_attr_readonly = true
config.load_defaults 7.1
ではこの振る舞いがデフォルトで有効になる。
Alex Ghiculescu, Hartley McGuire
同CHANGELOGより
参考: config.active_record.raise_on_assign_to_attr_readonly
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20221129: readonlyの属性に代入すると`ActiveRecord::ReadonlyAttributeError`を発生するようになった
unscope
で関連付けのpreload
やeager_load
も指定できるようになった。
includes
やjoins
などと同様に、unscope
で関連付けのpreload
やeager_load
を行う機能が追加された。サポートされているunscope
可能なスコープの完全なリストについては、ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES
を参照。
query.unscope(:eager_load, :preload).group(:id).select(:id)
David Morehouse
同CHANGELOGより
参考: 週刊Railsウォッチ20221129: 関連付けのpreload
やeager_load
をunscope
できるようになった
inspect
で暗号化済み属性をフィルタで自動的に除外するようになった。
この機能はデフォルトで有効になるが、以下のコンフィグを設定することで無効にできる。
config.active_record.encryption.add_to_filter_parameters = false
Hartley McGuire
同CHANGELOGより
この機能により、暗号化済み属性は自動的にログからも除外されるようになります。
参考: config.active_record.add_to_filter_parameters
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20221129: #inspect
実行時に暗号化済み属性を自動的にフィルタで除外する機能が追加された
レコードを#dup
したときにlocking_column
を解除するようになった。
この変更により、idやタイムスタンプなどのlocking_column
が複製されない問題が修正される。
car = Car.create!
car.touch
car.lock_version #=> 1
car.dup.lock_version #=> 0
Shouichi Kamiya, Seonggi Yang, Ryohei UEDA
同CHANGELOGより
参考: Rails API locking_column
-- ActiveRecord::Locking::Optimistic::ClassMethods
トランザクションを可能な限り早期に無効化するようになった。
TransactionRollbackError
例外をrescue
した後、トランザクションをフローの早い段階で無効化し、フレームワークがROLLBACK
ステートメントの発行をスキップするケースを増やす。
これが影響するのは、savepoint_errors_invalidate_transactions?
にtrue
を設定しているアダプタのみであり、現時点ではmysql2
アダプタにのみ影響する。
Nikita Vasilevsky
同CHANGELOGより
参考: Rails API savepoint_errors_invalidate_transactions?
-- ActiveRecord::ConnectionAdapters::Mysql2Adapter
ActiveRecord::Base
オブジェクトが発行するSQLクエリで複数カラムのリストを設定できるようになった。
複数カラムをリストとして設定可能になったことで、ActiveRecord::Base
オブジェクトを更新/削除/リロードしたときのSQLクエリ句のビルドで使われるようになった。
class Developer < ActiveRecord::Base
query_constraints :company_id, :id
end
developer = Developer.first.update(name: "Bob")
# => UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
Nikita Vasilevsky
同CHANGELOGより
参考: 週刊Railsウォッチ20221115: ActiveRecord::Base
オブジェクトのクエリでカラムのリストを指定可能になった
(PostgreSQL)schema.rbの外部キーやCHECK制約にvalidate
を追加するようになった。
従来は、外部キーやCHECK制約の追加にvalidate: false
を指定したかどうかがschema.rbに記録されていなかったため、データベースをスキーマからリストアすると外部キーやCHECK制約が誤ってバリデーションされる可能性があった。
Tommy Graves
同CHANGELOGより
参考: 週刊Railsウォッチ20221115: schema.rbの外部キーやCHECK制約にvalidate: false
を追加するようになった(PostgreSQL)
データベースアダプタの#execute
メソッドにallow_retry
オプションを渡せるようになった。
このオプションをtrue
に設定するとSQLステートメントがリトライされるようになる。リトライは、リトライ回数がデータベース設定のconnection_retries
値に達するまで、またはコネクション関連のエラーが発生するまで行われる。
Adrianna Chang
同CHANGELOGより
参考: 週刊Railsウォッチ20221115: DBアダプタの#execute
メソッドにallow_retry
オプションを渡せるようになった
データベース行が削除済みの場合にのみafter_commit :destroy
がトリガーされるようになった。
これにより、同じレコードに対してdestroy
が複数回呼び出された場合にafter_commit :destroy
コールバックが複数回トリガーされるのを防止する。
Ben Sheldon
同CHANGELOGより
参考: 週刊Railsウォッチ20221101: 同一レコードでafter_commit :destroy
の重複トリガーを解消
ciphertext_for
が返す値が暗号化されないバグを修正。
従来のciphertext_for
は、永続化されていないレコードなどから暗号化されていない平文を返していた。
Post.encrypts :body
post = Post.create!(body: "Hello")
post.ciphertext_for(:body)
# => "{\"p\":\"abc..."
post.body = "World"
post.ciphertext_for(:body)
# => "World"
修正後のciphertext_for
は、暗号化属性から常に暗号化済みテキストを返すようになった。
Post.encrypts :body
post = Post.create!(body: "Hello")
post.ciphertext_for(:body)
# => "{\"p\":\"abc..."
post.body = "World"
post.ciphertext_for(:body)
# => "{\"p\":\"xyz..."
Jonathan Hefner
同CHANGELOGより
参考: 週刊Railsウォッチ20221101: ciphertext_for
が暗号化前の値を返す問題を修正
テーブル名が長い場合にgroup
やcount
が誤った値を返すバグを修正。
Shota Toguchi, Yusaku Ono
同CHANGELOGより
この修正は、Rails 7.0.5でリリース済みです。
カラムのデフォルト値の暗号化を修正。
従来は、カラムのデフォルト値が設定されている暗号化属性がレコード作成時に暗号化されているように見えていたが、実際には暗号化されていなかった。
Book.encrypts :name
book = Book.create!
book.name
# => "<untitled>"
book.name_before_type_cast
# => "{\"p\":\"abc..."
book.reload.name_before_type_cast
# => "<untitled>"
修正後は、カラムのデフォルト値を設定した暗号化属性が暗号化されるようになった。
Book.encrypts :name
book = Book.create!
book.name
# => "<untitled>"
book.name_before_type_cast
# => "{\"p\":\"abc..."
book.reload.name_before_type_cast
# => "{\"p\":\"abc..."
Jonathan Hefner
同CHANGELOGより
Base
からconnection_handler
への委譲を非推奨化。
以下の呼び出しが非推奨化された。
Base.clear_all_connections!
Base.clear_active_connections!
Base.clear_reloadable_connections!
Base.flush_idle_connections!
今後これらのメソッドはコネクションハンドラで直接呼び出すこと。
Base
からconnection_handler
への委譲は今後のRailsで削除される予定。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API ActiveRecord::ConnectionAdapters::ConnectionHandler
ActiveRecord::QueryMethods#reselect
にもActiveRecord::QueryMethods#select
と同様にハッシュ値を渡せるようになった。
Sampat Badhe
同CHANGELOGより
# 同PRより(以下の2つは同じ)
Post.select(:title, posts: { title: :post_title })
Post.select(:title, :body).reselect(:title, posts: { title: :post_title })
参考: 週刊Railsウォッチ20221101: ActiveRecord::QueryMethods#reselect
にもカラムやエイリアスを含むハッシュを渡せるようになった
マイグレーションのカラム/テーブル管理メソッドに渡されるオプションが有効かどうかをバリデーションするようになった。
create_table
やadd_column
などのマイグレーション用メソッドに無効なオプションを渡すと、従来は単に無視されていたが、修正後はエラーを発生するようになった。
オプションのバリデーションは、新規作成されたマイグレーションに対してのみ適用される。
Guo Xiang Tan, George Wambold
同CHANGELOGより
参考: 週刊Railsウォッチ20221025: 新規マイグレーションのカラム/テーブル管理で無効なオプションが指定されるとraiseするようになった
QueryLogs
のタグフォーマットにデフォルトでSQLCommenter形式が使われるようになった。
詳しくは#46179を参照。
QueryLogs
でSQLCommenter形式のタグを無効にするには、config.active_record.query_log_tags_format = :legacy
を設定する。
デフォルトでは:sqlcommenter
が設定される。
Modulitos and Iheanyi
同CHANGELOGより
参考: Rails API ActiveRecord::QueryLogs
参考: config.active_record.query_log_tags_format
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20221018: QueryLogsでtags_format
オプションを指定可能になった
rakeタスク作成時にdatabase.ymlで任意のERBを書けるようになった。
環境設定にアクセスする場合でもdatabase.yml
に任意のERBを書けるようになった。
config.active_record.suppress_multiple_database_warning
設定は非推奨化された。
Eike Send
同CHANGELOGより
参考: RailsガイドのRails アプリケーションを設定するには、このconfig.active_record.suppress_multiple_database_warning
はこれまで記載されていません。
参考: 週刊Railsウォッチ20221018: database.ymlのYAMLキーに任意のERBを書けるようになった
カラム定義が重複していた場合のエラーメッセージにテーブル名も出力されるようになった。
マイグレーションでテーブルのカラム定義が重複している場合に、問題が生じたテーブル名を含むエラーメッセージが表示される。
Petrik de Heus
同CHANGELOGより
# 同PRより: テーブル名'testings'が出力される
you can't define an already defined column 'testing_column' on 'testings'.
仮想のdatetime
カラムがデフォルトでprecision: nil
になっていたのを修正。
この修正の前は、仮想のdatetime
カラムのデフォルト精度が通常のdatetime
カラムのデフォルト精度と同じになっておらず、以下の2つが誤って同等になっていた。
t.virtual :name, type: datetime, as: "expression"
t.virtual :name, type: datetime, precision: nil, as: "expression"
この変更では、デフォルト精度の探索が修正され、datetime
のデフォルト精度が仮想カラムでも通常カラムでも一致するようになった。
Sam Bostock
同CHANGELOGより
この修正は、Rails 7.0.5でリリース済みです。
#quote_string
で#with_raw_connection
のコネクションを使うようになった。
これにより、#with_raw_connection
が提供する再接続・リトライロジックによって#quote_string
がラップされるようになる。
Adrianna Chang
同CHANGELOGより
参考: Rails API quote_string
-- ActiveRecord::ConnectionAdapters::Quoting
失効日時を指定するexpires_at
オプションをsigned_id
に追加。
Shouichi Kamiya
同CHANGELOGより
# 同PRより
Account.find_signed(@account.signed_id(expires_at: 1.minute.from_now)
参考: Rails API signed_id
-- ActiveRecord::SignedId
クエリのリトライ期間に上限を設定できるようになった。
#44576と#44591で行われた作業を基に、データベースコネクションの自動再接続ロジックを拡張してタイムアウト制限を考慮するようになった。クエリが最初に試行されてから一定時間経過すると、クエリは再試行されなくなる。この値にはデフォルトではnil
が設定されている(経過時間に関係なくすべての再試行可能なクエリが再試行される)。これはデータベース設定のretry_deadline
オプションで変更可能。
Adrianna Chang
同CHANGELOGより
# 同PRより
development:
adapter: mysql2
retry_deadline: 5 # 5秒経過したらリトライを停止
クエリキャッシュが誤った値を返すことがあるバグを修正。
#46044を参照。
Aaron Patterson
同CHANGELOGより
MySQLDatabaseTasks
でMySQLのSSLモードオプションをサポート。
データベースサーバーの識別情報を検証するには、--ssl-mode
オプションにVERIFY_CA
またはVERIFY_IDENTITY
を設定する必要がある。従来、データベース作成やstructureダンプなどのMySQLデータベースタスクでこのオプションが無視されていた。
Petrik de Heus
同CHANGELOGより
参考: 週刊Railsウォッチ20221011: dbconsoleコマンドとMySQLDatabaseTasksに--ssl-mode
オプションを追加
ActiveRecord::InternalMetadata
を別オブジェクトに移動。
ActiveRecord::InternalMetadata
はActiveRecord::Base
を継承しなくなり、connection
を渡して初期化する独立したオブジェクトになった。
このクラスはprivateであり、アプリケーションから直接使うべきではない。スキーママイグレーションのテーブルとやりとりする必要がある場合は、ActiveRecord::Base.connection.schema_migration
のように直接コネクションにアクセスすること。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API ActiveRecord::InternalMetadata
ActiveSupport::Duration
を整数値として式展開することを非推奨化。
SQL文字列テンプレート内でActiveSupport::Duration
を式展開にバインドするパラメータとして利用することが非推奨化された。
この非推奨警告表示を回避するには、明示的にDuration
をより具体的なデータベース型に変換すること。
たとえば、Duration
を秒単位の整数値として利用したい場合は、以下のように書くこと。
Record.where("duration = ?", 1.hour.to_i)
Duration
をISO 8601形式の文字列として使いたい場合は、以下のように書くこと。
Record.where("duration = ?", 1.hour.iso8601)
Aram Greenman
同CHANGELOGより
参考: この変更には後方互換用のコンフィグはありません(#44438コメント)。
QueryMethods
の#in_order_of
による並べ替えが、カラム名が文字列の場合にも使えるようになった。
Post.in_order_of("id", [4,2,3,1]).to_a
Post.joins(:author).in_order_of("authors.name", ["Bob", "Anna", "John"]).to_a
Igor Kasyanchuk
同CHANGELOGより
参考: Rails API in_order_of
-- ActiveRecord::QueryMethods
ActiveRecord::SchemaMigration
を別オブジェクトに移動。
ActiveRecord::SchemaMigration
はActiveRecord::Base
を継承しなくなり、connection
を渡して初期化する独立したオブジェクトになった。
このクラスはprivateであり、アプリケーションから直接使うべきではない。スキーママイグレーションのテーブルとやりとりする必要がある場合は、ActiveRecord::Base.connection.schema_migration
のように直接コネクションにアクセスすること。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API ActiveRecord::SchemaMigration
all_connection_pools
を非推奨化し、connection_pool_list
にオプションを明示的に渡すようにした。
#45924に続いて、all_connection_pools
を非推奨化した。
connection_pool_list
には明示的にrole
引数を渡すようになった。この引数に:all
を渡すことで、アプリケーションで新しい振る舞いを選択できるようになる。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API connection_pool_list
-- ActiveRecord::ConnectionAdapters::ConnectionHandler
コネクションハンドラのメソッドがすべてのコネクションプールで動作するよう修正。
以下のメソッドが、デフォルトですべてのコネクションプールで動作するようになった。
active_connections?
clear_active_connections!
clear_reloadable_connections!
clear_all_connections!
flush_idle_connections!
従来は、ロールを指定しない場合にデフォルトでcurrent_role
ロールまたは:writing
ロールが使われていた。
Eileen M. Uchitelle
同CHANGELOGより
参考: 週刊Railsウォッチ20221003: コネクションハンドラメソッドのバグを修正
関連: Allow ActiveRecord::QueryMethods#reselect to accept a hash by sampatbadhe · Pull Request #46253 · rails/rails
ActiveRecord::QueryMethods
の#select
にハッシュ値を渡せるようになった。
従来は、select
でカラム定義やselect
のエイリアス定義を行うには生SQLまたはシンボルを渡すしかなかった。
この変更によって、以下のようにhash
を引数として渡せるようになる。
Post.joins(:comments).select(posts: [:id, :title, :created_at], comments: [:id, :body, :author_id])
#=> "SELECT \"posts\".\"id\", \"posts\".\"title\", \"posts\".\"created_at\", \"comments\".\"id\", \"comments\".\"body\", \"comments\".\"author_id\"
# FROM \"posts\" INNER JOIN \"comments\" ON \"comments\".\"post_id\" = \"posts\".\"id\""
Post.joins(:comments).select(posts: { id: :post_id, title: :post_title }, comments: { id: :comment_id, body: :comment_body })
#=> "SELECT posts.id as post_id, posts.title as post_title, comments.id as comment_id, comments.body as comment_body
# FROM \"posts\" INNER JOIN \"comments\" ON \"comments\".\"post_id\" = \"posts\".\"id\""
Oleksandr Holubenko, Josef Šimánek, Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20220926: ActiveRecord::QueryMethods#select
にハッシュを渡せるようになった
ActiveRecord::Persistence
の#becomes
で仮想属性を使えるようになった。
ソースクラスとターゲットクラスの属性セットが異なる場合は、ターゲットクラスの属性を追加する形で属性を適応させるようになる。
class Person < ApplicationRecord
end
class WebUser < Person
attribute :is_admin, :boolean
after_initialize :set_admin
def set_admin
write_attribute(:is_admin, email =~ /@ourcompany\.com$/)
end
end
person = Person.find_by(email: "email@ourcompany.com")
person.respond_to? :is_admin
# => false
person.becomes(WebUser).is_admin?
# => true
Jacopo Beschi, Sampson Crowley
同CHANGELOGより
参考: Rails API becomes
-- ActiveRecord::Persistence
参考: 週刊Railsウォッチ20220920: ActiveRecord::Persistence#becomes
をvirtual attributeに適応させる
Enumerable#
のin_order_of
の振る舞いに合わせるため、ActiveRecord::QueryMethods
の#in_order_of
がnil
を扱えるよう修正。
たとえば、Post.in_order_of(:title, [nil, "foo"])
でタイトルがnil
のpostsも含まれるようになる。これはPost.all.to_a.in_order_of(:title, [nil, "foo"])
の振る舞いと同じ。
fatkodima
同CHANGELOGより
参考: Rails API in_order_of
-- ActiveRecord::QueryMethods
参考: Rails API in_order_of
-- Enumerable
参考: 週刊Railsウォッチ20220905: ActiveRecord::QueryMethods#in_order_of
のソート対象の値がnil
でも動作するよう修正
add_timestamps
が発行するSQLステートメントが1つだけになるよう最適化。
add_timestamps :my_table
上によって以下のSQLが生成されるようになる。
ALTER TABLE "my_table" ADD COLUMN "created_at" datetime(6) NOT NULL, ADD COLUMN "updated_at" datetime(6) NOT NULL
Iliana Hadzhiatanasova
同CHANGELOGより
参考: §3.9 changeメソッドを使う -- Active Record マイグレーション - Railsガイド
マイグレーションコマンドにdrop_enum
を追加(PostgreSQLのみ)。
これはcreate_enum
と逆の動作。enumを削除する前には、そのenumに依存しているカラムを必ず削除しておくこと。
Alex Ghiculescu
同CHANGELOGより
Rails 7: PostgreSQLのカスタムenum型が使いやすくなった(翻訳)
CHECK制約の削除でif_exists
をサポート。
remove_check_constraint
メソッドにif_exists
オプションを渡せるようになった。if_exists: true
を設定すると、そのCHECK制約が存在しない場合にエラーを発生しなくなる。
Margaret Parsa and Aditya Bhutani
同CHANGELOGより
参考: §3.9 changeメソッドを使う -- Active Record マイグレーション - Railsガイド
参考: 週刊Railsウォッチ20220822: CHECK制約の削除でif_exists
オプションが利用可能になる
find_or_create_by
でRecordNotUnique
が発生した場合はfind
をリトライするようになった。
find_or_create_by
は本質的に競合がつきものなので、適切なunique制約が設定されているかどうかで「重複レコードを作成する」か「ActiveRecord::RecordNotUnique
で失敗する」かが決まる。
このユースケース向けにcreate_or_find_by
が導入されたが、レコードが既に存在する可能性が非常に高い場合は、INSERTはSELECTよりも多くのデータ送信が必要になり、データベース側の作業も増加するため、効率がかなり悪くなる。また、データベースによっては、主キーのインクリメント(望ましくない)が消費される可能性もある。
そのため、レコードが既に存在する可能性が非常に高いユースケースでは、create
がActiveRecord::RecordNotUnique
で失敗した場合はfind
を再試行することで競合が発生しないようにできる。これはテーブルで適切なunique制約が設定されていることが前提となる。さもないと、find_or_create_by
で引き続き重複レコードが発生する。
Jean Boussier, Alex Kitchens
同CHANGELOGより
参考: §19.1 find_or_create_by
-- Active Record クエリインターフェイス - Railsガイド
参考: Rails API create_or_find_by
-- ActiveRecord::Relation
参考: 週刊Railsウォッチ20220822: find_or_create_by
でRecordNotUnique
エラーの場合にfind
をリトライするようになった
Active Recordのデータベースアダプタに、よりシンプルなコンストラクタAPIが導入された。
従来は、データベースアダプタが再接続をサポートするために新しいraw_connection
のビルド方法を知っている必要があったが、最初の確立済みコネクションを渡されることも期待されていた。
改修後は、アダプタのインスタンスを手動で作成する場合は、コンフィグ用ハッシュを1個渡すだけで、必要に応じて実際の接続が確立するようになった。
Matthew Draper
同CHANGELOGより
可能な場合は、DBプールのチェックアウト中にSELECT 1
による余分なコネクションバリデーション用クエリを避けるようになった。
リクエスト中の最初のクエリが冪等であることがわかっている場合は、これを用いてコネクションを直接バリデーションできるので、ネットワークのやりとりが削減される。
Matthew Draper
同CHANGELOGより
コネクションが切断された場合、安全であればリクエストの途中でもデータベースコネクションを自動で再接続するようになった。
冪等であることがわかっているクエリを実行しようとしてエラーが発生した場合、かつトランザクション内でない場合は、直ちにデータベースサーバーに再接続しても安全である。今後はこれがデフォルトの振る舞いになる。
新しいデフォルトの振る舞いは常に安全でなければならない。この振る舞いをサポートするため、どのクエリを冪等と認識するかについては保守的なアプローチを取っている。ただし、この振る舞いは、データベースコネクションのconnection_retries
オプションに0
を設定することで無効にできる。
Matthew Draper
同CHANGELOGより
参考: Rails API connection_retries
-- ActiveRecord::ConnectionAdapters::AbstractAdapter
PostgreSQL拡張に依存しているオブジェクトが存在する場合は、その拡張の削除を回避するようになった。
従来は、拡張を削除すると依存オブジェクトも暗黙で削除されていた。
改修後は、このような削除を行うとエラーを発生するようになった。
マイグレーションで以下のように拡張を強制削除することも可能。
disable_extension :citext, force: :cascade
修正: #29091
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20220801: PostgreSQL拡張機能に依存するオブジェクトがある場合は削除しないようになった
ネストしたSQL関数を安全なSQL文字列として扱えるようになった。
Michael Siegfried
同CHANGELOGより
# 同PRより
Post.pluck(Arel.sql("length(trim(title))"))
参考: 週刊Railsウォッチ20220725: ネストしたSQL関数を安全なSQL文字として許容する
destroy_association_async_job=
に設定するクラス(定数)を、クラス名の文字列でも設定できるようになった。
ActiveRecord::Base
とActiveJob::Base
の間のオートローディングを先延ばしするようにし、ActiveRecord::DestroyAssociationAsyncJob
の設定をActive JobからActive Recordに移動した。
ActiveRecord::ActiveJobRequiredError
は非推奨化された。
これにより、ジョブクラスが読み込み不能な場合はNameError
が発生するようになった。
また、関連付けでdependent: :destroy_async
が宣言され、かつジョブクラスが未設定の場合はActiveRecord::ConfigurationError
が発生するようになった。
Ben Sheldon
同CHANGELOGより
参考: Rails API destroy_association_async_job
-- ActiveRecord::Core
参考: config.active_record.destroy_association_async_job
-- Rails アプリケーションを設定する - Railsガイド
ActiveRecord::Store
におけるハッシュのシリアライズを通常のハッシュとして行うよう修正。
従来はActiveSupport::HashWithIndifferentAccess
としてシリアライズしていたが、これは無駄が多く、YAML safe_load
で問題を生じる。
Jean Boussier
同CHANGELOGより
この修正は、Rails 7.0.4と6.1.7でリリース済みです。
PostgreSQLのタイムゾーン対応型timestamptz
を追加。
データベース内でtimestamp with time zone
値を正しく解析するにはこの型が必要。
これを使いたくない場合は、イニシャライザに以下を追加することで無効にできる。
ActiveRecord::Base.time_zone_aware_types -= [:timestamptz]
Alex Ghiculescu
同CHANGELOGより
この修正は、Rails 7.0.4でリリース済みです。
ActiveRecord::Base.generates_token_for
APIを新たに追加。
現在のsigned_id
は、パスワードのリセットなどでトークンを生成する役割を担当している。しかしsigned_id
にはレコードのステートを反映できないので、トークンを1回だけ使う場合は、少なくとも期限切れまでデータベースでトラッキングしなければならなくなる。
generates_token_for
を使うことで、トークンにレコードのデータを埋め込めるようになる。このトークンを用いてレコードを取得すると、トークンのデータと現在のレコードのデータが比較される。両者が一致しない場合、トークンは無効と見なされるため、期限切れした場合と同じ扱いになる。
例:
class User < ActiveRecord::Base
has_secure_password
generates_token_for :password_reset, expires_in: 15.minutes do
# `password_salt`(`has_secure_password`で定義される)は、
# そのパスワードのsaltを返す。パスワードが変更されるとsaltも変更されるので、
# パスワードが変更されるとこのトークンは無効になる。
BCrypt::Password.new(password_digest).salt[-10..]
end
end
user = User.first
token = user.generate_token_for(:password_reset)
User.find_by_token_for(:password_reset, token) # => user
user.update!(password: "new password")
User.find_by_token_for(:password_reset, token) # => nil
Jonathan Hefner
同CHANGELOGより
参考: Rails API generates_token_for
-- `ActiveRecord::TokenFor::ClassMethods
Active Recordのテーブル全体をイテレーションするバッチを最適化。
従来のin_batches
では、全idを取得したうえでバッチごとにIN
ベースのクエリを構築していた。テーブル全体をイテレーションする場合、この方法では不要なidまで読み込まれてしまい、IN
クエリの項目数が増えて遅くなる。
改修後は、テーブル全体のイテレーションでは範囲指定(id >= x AND id <= y
)をデフォルトで使うようになり、イテレーションが数倍高速になる。たとえば、PostgreSQLで1000万件のレコードを持つテーブルでテストした場合のクエリ時間は253s
-> 30s
、更新は288s
->124s
、削除は268s
-> 83s
となった。
このイテレーションをデフォルトで使うのはテーブル全体をイテレーションする場合に限られる。この振る舞いは、use_ranges: false
オプションを渡すことで無効化できる。
テーブル全体のイテレーションで、 archived_at: nil
のような条件だけを指定する場合(かつアーカイブ済みのレコードがごく一部しかない場合)、このアプローチを採用する意義がある。
Project.where(archived_at: nil).in_batches(use_ranges: true) do |relation|
# 何かする
end
詳しくは#45414を参照。
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20220711: Active Recordのin_batches
でuse_ranges: true
を指定可能になった
.with
クエリメソッドを追加。
CTE(Common Table Expression)を手軽に構築してActiveRecord::Relation
を得られるようになった。
Post.with(posts_with_comments: Post.where("comments_count > ?", 0))
# => ActiveRecord::Relation
# WITH posts_with_comments AS (SELECT * FROM posts WHERE (comments_count > 0)) SELECT * FROM posts
Vlado Cingel
同CHANGELOGより
参考: PostgreSQL 15ドキュメント 7.8. WITH問い合わせ(共通テーブル式)
参考: 週刊Railsウォッチ20220711: ActiveRecord::Relation
にCTEを利用できるwith
メソッドが追加
同一のコネクションプールが既に存在する場合は新しいコネクションを確立しないようになった。
従来は、既に確立済みのコネクションを持つクラスで establish_connection
が呼び出されると、設定が同じかどうかに関係なく既存のコネクションが削除された。
改修後は、新しいコネクションと同じ値を持つコネクションプールが見つかった場合、新しいコネクションではなく既存のコネクションを返すようになった。
アプリケーションのコードが、新しいコネクションが既存のコネクションと同一かどうかにかかわらず確立される振る舞いに依存している場合、振る舞いがわずかに変更されることになる。
古い振る舞いに戻したい場合は、新しいコネクションを確立する前にActiveRecord::Base#remove_connection
を呼び出す必要がある。設定を変えてestablish_connection
を呼び出す場合の振る舞いは、従来と同様になる。
Eileen M. Uchitelle
同CHANGELOGより
参考: Rails API establish_connection
-- ActiveRecord::ConnectionHandling
Allow db:prepare
to load schema if database already exists but is empty; also dumps schema after migrations by bensheldon · Pull Request #45464 · rails/rails
db:prepare
タスクを更新。
初期化されていないデータベースが存在する場合はスキーマを読み込み、残りのマイグレーションがあれば実行して、その後スキーマをダンプするように変更した。
Ben Sheldon
同CHANGELOGより
参考: 週刊Railsウォッチ20220719: 空のデータベースが存在していてもdb:prepare
でスキーマを読み込み可能にした
(PostgreSQLのみ)範囲型のtsrange
カラムとtstzrange
カラムでタイムゾーンを認識するサポートを修正。
# データベースのマイグレーション内
add_column :shops, :open_hours, :tsrange, array: true
# アプリのコンフィグ内
ActiveRecord::Base.time_zone_aware_types += [:tsrange]
# このコードのtimeがアプリのタイムゾーンに正しく変換されるようになる
Shop.create!(open_hours: [Time.current..8.hour.from_now])
Wojciech Wnętrzak
同CHANGELOGより
この修正は、Rails 7.0.4でリリース済みです。
参考: Rails API ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnMethods
参考: PostgreSQL 15ドキュメント 8.17. 範囲型
マイグレーションの実行にStrategyパターンを導入。
デフォルトでは、メソッドをコネクションアダプタに委譲するstrategyオブジェクトをマイグレーションで使う。利用側(consumer)は、カスタムのstrategyオブジェクトを実行することでマイグレーションの実行方法を変更できるようになる。
Adrianna Chang
同CHANGELOGより
参考: config.active_record.migration_strategy
-- Rails アプリケーションを設定する - Railsガイド
参考: Strategy パターン - Wikipedia
参考: 週刊Railsウォッチ20220704: マイグレーションをExecutionStrategy
でカスタマイズ可能にする
アダプタ設定ファイルのオプションで外部キーを禁止できるようになった。
新しいforeign_keys
オプションはdatabase.yml
に追加可能。これにより、背後のデータベースで外部キー制約がサポートされていても外部キー制約をスキップできるようになる。
利用法:
development:
<<: *default
database: storage/development.sqlite3
foreign_keys: false
Paulo Barros
同CHANGELOGより
参考: 週刊Railsウォッチ20220704: database.ymlでforeign_keys: false
を指定可能になった
単数形の関連付けに対する非推奨化警告をコンフィグで設定できるようになった。
このコンフィグは、単数形の関連付け名をwhere
内で複数形で参照する非推奨の書き方(遅くなる)に警告を表示するかどうかを制御する。
以下の設定にするとパフォーマンスが改善する。
config.active_record.allow_deprecated_singular_associations_name = false
Adam Hess
同CHANGELOGより
このコンフィグは、Rails 7.1ではデフォルトでfalse
になります。
参考: config.active_record.allow_deprecated_singular_associations_name
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20220704: 関連付け先の単数形の名前をwhere
内から複数形で参照すると警告を出す
トランザクション内でレコードをsave
すると、最も新しいインスタンスでトランザクションコールバックを実行するようになった。
1つのトランザクション内で複数のActive Recordインスタンスが同じレコードを変更する場合、そのうちの1つだけがafter_commit
やafter_rollback
を実行する。
Railsでどのインスタンスがコールバックを受け取るかを指定できるよう、config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction
コンフィグが追加された。フレームワークはデフォルトで新しいロジックを使うよう変更された。
config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction
がtrue
の場合は、インスタンスのステートがstaleしていても(=古くなっても)、最初に保存したインスタンスでトランザクションコールバックが実行される。
これがfalse
の場合は7.1からフレームワークのデフォルトになるが、トランザクションコールバックはステートが最新のインスタンスで実行される。インスタンスは以下のように選択される。
- 一般に、トランザクションコールバックは最新のインスタンスで実行され、トランザクション内で指定のレコードを保存する。
- ただし例外が2つある。
- トランザクション内でレコードを作成して別のインスタンスで更新すると、
after_create_commit
は2番目のインスタンスで実行される。これは、インスタンスのステートに基づいてナイーブに実行されるafter_update_commit
コールバックの代わりとなる。
- レコードがトランザクション内で削除されると、
after_destroy_commit
コールバックは最後に削除されたインスタンスで実行される。これは、たとえstaleしたインスタンスがその後更新を行ったとしても同様で、この更新はどの行にも影響しない。
Cameron Bothner and Mitch Vollebregt
同CHANGELOGより
参考: 週刊Railsウォッチ20220620: トランザクション内に同一モデルのインスタンスが複数ある場合にどのインスタンスからコールバックを呼び出すかを変更
SQLite3Adapter
で"strict strings"モードを有効にした。
SQLite3で"strict strings"モードを設定することで、二重引用符(""
)で囲まれた文字列リテラルが無効になった。
SQLite3では、二重引用符で囲んだ文字列リテラルにいくつかの癖がある。
最初は二重引用符で囲んだ文字列を識別子名とみなそうとするが、存在しない場合は文字列リテラルとみなす。この振る舞いのせいで、タイポがあっても通知されない。たとえば、存在しないカラムに対してインデックスを作成できてしまう。
詳しくは以下のSQLite3ドキュメントを参照。
この振る舞いを無効にしたい場合は、以下の設定で行える。
# config/application.rb
config.active_record.sqlite3_adapter_strict_strings_by_default = false
修正: #27782
fatkodima, Jean Boussier
同CHANGELOGより
参考: config.active_record.sqlite3_adapter_strict_strings_by_default
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20220620: SQLiteのdatabase.ymlにデフォルトで:strict
オプションを追加
リレーションのcache_version
がstaleする(古くなる)可能性がある問題を修正。
従来は、リレーションオブジェクトでreset
を呼び出しても@cache_versions
がリセットされていなかったため、最新の正しいデータがあるにもかかわらず、古いcache_version
の値が返されて混乱することがあった。
利用法:
developers = Developer.all
developers.cache_version
Developer.update_all(updated_at: Time.now.utc + 1.second)
developers.cache_version # cache_versionがstaleする
developers.reset
developers.cache_version # 最新の正しいcache_versionを返す
修正: #45341
Austen Madden
同CHANGELOGより
参考: 週刊Railsウォッチ20220620: Active Recordリレーションのreset
でcache_version
がリセットするよう修正
(PostgreSQLのみ)EXCLUDE制約をサポート。
add_exclusion_constraint
remove_exclusion_constraint
add_exclusion_constraint :invoices, "daterange(start_date, end_date) WITH &&", using: :gist, name: "invoices_date_overlap"
remove_exclusion_constraint :invoices, name: "invoices_date_overlap"
EXCLUDE制約について詳しくはPostgreSQLドキュメントのCREATE TABLE ... EXCLUDE ...
を参照。
Alex Robbin
同CHANGELOGより
参考: 週刊Railsウォッチ20220620: (PostgreSQLのみ)EXCLUDE制約のサポートが追加
change_column_null
の第3引数がブーリアンでない場合はエラーを発生するよう修正。
従来は、change_column_null
の第3引数がブーリアンでない場合にtruthyとして扱われ、カラムがnull許容になった。この振る舞いは予想に反するので、true
またはfalse
のみを渡せるよう変更された。
change_column_null :table, :column, true # good
change_column_null :table, :column, false # good
change_column_null :table, :column, from: true, to: false # raiseする(従来はnullableカラムになった)
Alex Ghiculescu
同CHANGELOGより
参考: 週刊Railsウォッチ20220620: change_column_null
にブーリアン以外の値を渡すとエラーになるように修正
テーブル名の長さに上限を設けた。
修正: #45130
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20220620: テーブル名の長さに上限を設定
CHECK制約サポートのため、MariaDBの最小バージョン指定を10.2.22
に修正。
Eddie Lebow
同CHANGELOGより
PostgreSQLのHstore
データ型のデシリアイズで再発した不具合を修正。
edsharp
同CHANGELOGより
参考: PostgreSQL 15ドキュメント F.18. hstore
PostgreSQLインデックスの有効性をチェックするvalid: true
オプションを追加。
connection.index_exists?(:users, :email, valid: true)
connection.indexes(:users).select(&:valid?)
fatkodima
同CHANGELOGより
参考: 週刊Railsウォッチ20220606: PostgreSQL用のindex_exists?
にvalid:
キーワード引数が追加
主キーがないモデルのeager_load
が正しく行われない問題を修正。
Anmol Chopra, Matt Lawrence, and Jonathan Hefner
同CHANGELOGより
プルリクメッセージには、通常のActive Recordでも、データベースVIEWを使っている場合や、以下のようなメソッドチェインでこの問題が起きていたと書かれています。
my_instance.includes(:model_without_primary_key).order('model_without_primary_key.name')
参考: 週刊Railsウォッチ20220606: 主キーのないモデルのeager_load
を修正
uniqueインデックスのあるフィールドで変更が生じなかった場合は、フィールドのuniqueness
バリデーションを回避するようになった。
従来は、レコードをsave
したときにuniqueness
バリデーションが設定されている属性でuniqueness
チェックのためのクエリが余分に送信されていた。これは属性に変更がなかった場合でも発生していた。
これに対応するuniqueインデックスがデータベース側にあれば、永続化でこのバリデーションが失敗することはありえないので、このバリデーションを安全にスキップできる。
fatkodima
同CHANGELOGより
参考: §2.12 uniqueness
-- Active Record バリデーション - Railsガイド
参考: 週刊Railsウォッチ20220531: uniqueness指定のフィールドが変更されていない場合のバリデーションを回避
MySQLアダプタでvariables["sql_auto_is_null"] = 0
を設定しないようになった。
この設定はMySQL 5.5以降デフォルトでオフになったので、手動でわざわざオフにする必要はない。
Adam Hess
同CHANGELOGより
参考: PDF MySQL 5.5 Release Notes
attr_readonly
カラムにtouch
したらActiveRecord::ActiveRecordError
を発生するよう修正。
fatkodima
同CHANGELOGより
同プルリクメッセージでは以下のように書かれています。
update_attribute
およびupdate_attributes
ではエラーになる
- 属性への代入や
update
は、readonly属性についてはsave
時に単に無視される(以下のAPIドキュメントに書かれている通り)。
参考: Rails API attr_readonly
-- ActiveRecord::ReadonlyAttributes::ClassMethods
SQLスキーマダンプで除外したいテーブルを正規表現で指定できるようになった。
ActiveRecord::SchemaDumper.ignore_tables = [/^_/]
fatkodima
同CHANGELOGより
参考: ActiveRecord::SchemaDumper.ignore_tables
-- Rails アプリケーションを設定する - Railsガイド
矛盾のあるリレーションで計算メソッドを実行するときにクエリ送信を回避するよう修正。
従来は、User.where(id: []).count
のように矛盾のあるリレーションを渡すと計算時にクエリが送信されていた。修正により、このようなシナリオでクエリを送信しなくなった。
該当する計算メソッドは以下のとおり。
count
sum
average
minimum
maximum
Luan Vieira, John Hawthorn and Daniel Colson
同CHANGELOGより
参考: §22 計算 -- Active Record クエリインターフェイス - Railsガイド
Rails 7: リレーションの結果が空になる計算でクエリ送信を回避する(翻訳)
insert_all
とupsert_all
でエイリアス属性も指定できるようになった。
class Book < ApplicationRecord
alias_attribute :title, :name
end
Book.insert_all [{ title: "Remote", author_id: 1 }], returning: :title
fatkodima
同CHANGELOGより
参考: Rails API insert_all
-- ActiveRecord::Persistence::ClassMethods
参考: Rails API upsert_all
-- ActiveRecord::Persistence::ClassMethods
Rails 7: insert_allとupsert_allで属性のエイリアスを指定可能になる(翻訳)
カラムの暗号化属性でデータベースのデフォルト値をサポート。
これにより、カラムに定義された暗号化属性にデフォルト値を設定できるようになる。値は作成時に暗号化される。
改修前は、config.active_record.encryption.support_unencrypted_data
にtrue
を設定しないとエラーになっていた。
Jorge Manrubia and Dima Fatko
同CHANGELOGより
参考: §6.1.1 config.active_record.encryption.support_unencrypted_data
-- Active Record と暗号化 - Railsガイド
参考: 週刊Railsウォッチ20220516: デフォルト値付きのカラムで暗号化属性をサポート
DatabaseSelector::Resolver
ミドルウェアのreading_request?
がオーバーライド可能になった。
デフォルトの実装ではリクエストがget?
またはhead?
かどうかをチェックしているが、この振る舞いを自由に変更できるようになった。
このメソッドがtrue
を返すとResolver#read
が呼び出されるようになり、リクエストがreplicaデータベースによっても配信されるようになる。
Alex Ghiculescu
同CHANGELOGより
参考: Rails API ActiveRecord::Middleware::DatabaseSelector
Rails 7: マルチプルDBのreading_request?がカスタマイズ可能になった(翻訳)
Rails 6.1から非推奨化されていたActiveRecord.legacy_connection_handling
を削除。
Eileen M. Uchitelle
同CHANGELOGより
参考: §2.1 データベース単位のコネクション切り替え -- Ruby on Rails 6.1 リリースノート - Railsガイド
参考: 週刊Railsウォッチ20220411: legacy_connection_handling
を削除
rails db:schema:{dump,load}
でコンフィグ前にENV["SCHEMA_FORMAT"]
をチェックするようになった。
rails db:structure:{dump,load}
は既に非推奨化されているため、スキーマをSQL形式とRuby形式のどちらでも手軽に(=コンフィグを変更せずに)ダンプできる方法がなかった。
この改修により、以下のように環境変数を設定することでこれを行えるようになった。
SCHEMA_FORMAT=sql rake db:schema:dump
Alex Ghiculescu
同CHANGELOGより
この変更は、Rails 7.0.4でリリース済みです。
なおconfig.active_record.schema_format
のデフォルトは:ruby
です。
参考: §3.8.10 config.active_record.schema_format
-- Rails アプリケーションを設定する - Railsガイド
Rails 7: rails db:schema:dumpやloadのスキーマ形式を環境変数で指定可能になった(翻訳)
Rails: db:structure:loadとdb:structure:dumpタスクが非推奨化(翻訳)
MariaDBでのデフォルトSQL関数サポートを修正。
db/schema.rbへのダンプでデフォルト関数名が正しく書き込まれていなかったため、db:schema:load
を実行しても正しく動作しなかった。今後、より多くの関数が新規レコードの保存で文字列コンテンツとして追加されるようになるだろう。
kaspernj
同CHANGELOGより
参考: 週刊Railsウォッチ20220328: MariaDBのデフォルト関数サポートを修正
非同期バッチサイズを指定するactive_record.destroy_association_async_batch_size
コンフィグを追加。
これにより、アプリケーションでの関連付けにdependent: :destroy_async
オプションを指定して、単一のバックグラウンドジョブで削除する最大レコード数を指定できるようになる。デフォルトでは、現在の振る舞いを変えない(親レコードを削除すると、すべての依存レコードが単一のバックグラウンドジョブで削除される)。依存レコード数がこの設定を超えると、レコードの削除が複数のバックグラウンドジョブに分割されるようになる。
Nick Holden
同CHANGELOGより
参考: config.active_record.destroy_association_async_batch_size
-- Rails アプリケーションを設定する - Railsガイド
Rails 7: バックグラウンドジョブで削除する最大レコード数を指定可能になった(翻訳)
remove_foreign_key
に:if_exists
オプションを指定すると、外部キーが実際に存在している場合にエラーになっていたのを修正。
fatkodima
同CHANGELOGより
参考: §3.7 外部キー -- Active Record マイグレーション - Railsガイド
PostgreSQLのstructure dumpの--no-comments
フラグを廃止。
これにより、スキーマでカスタムコメントを使っている一部のアプリが動かなくなる。
structureダンプにコメントを含めたくない場合は、以下を設定できる。
ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = ['--no-comments']
Alex Ghiculescu
同CHANGELOGより
参考: §6 Structure Dumpについて -- Active Record と PostgreSQL - Railsガイド
フィクスチャのアクセサでメモリフットプリントを削減。
従来は、フィクスチャのアクセサをdefine_method
でeagerに定義していたため、フィクスチャやテストスイートの量が増えるとメモリ使用量に直接影響していた。
改修後は、フィクスチャのアクセサをmethod_missing
で実装したことで、メモリやCPUのオーバーヘッドが大きく軽減される。
Jean Boussier
同CHANGELOGより
参考: 週刊Railsウォッチ20220308: フィクスチャのメモリフットプリントを削減
参考: Module#define_method
(Ruby 3.2 リファレンスマニュアル)
参考: BasicObject#method_missing
(Ruby 3.2 リファレンスマニュアル)
config.active_record.destroy_association_async_job
コンフィグの不具合を修正。
config.active_record.destroy_association_async_job
は、dependent: :destroy_async
オプションを指定したhas_many
関連付けに対して行う削除をバックグラウンドで実行できるようにすべき。
従来はこのdependent: :destroy_async
オプションが無視されていたため、ActiveRecord::DestroyAssociationAsyncJob
による削除が常にバックグラウンドで実行されていた。
Nick Holden
同CHANGELOGより
参考: config.active_record.destroy_association_async_job
-- Rails アプリケーションを設定する - Railsガイド
参考: 週刊Railsウォッチ20220221: Active Recordのdestroy_association_async_job
コンフィグが効くように修正
MySQLアダプタ: change_column_comment
でカラムのAUTO_INCREMENT
が失われないよう修正。
fatkodima
同CHANGELOGより
参考: Rails API change_column_comment
-- ActiveRecord::ConnectionAdapters::SchemaStatements
MySQLアダプタで、数値がActiveSupport::Duration
とRational
の場合の引用符処理を修正。
Kevin McPhillips
同CHANGELOGより
参考: 週刊Railsウォッチ20220221: mysql2アダプタでActiveSupport::Duration
を適切に扱うよう修正
order
でカラムにCOLLATE
を指定した場合(例: title COLLATE "C"
)にも、SQL関数を指定したときと同様に安全なSQL文字として扱えるようになった。
Shugo Maeda
同CHANGELOGより
参考: Allow column name with function (e.g. length(title)
) as safe SQL string by kamipo · Pull Request #36448 · rails/rails
参考: 週刊Railsウォッチ20220221: order
でCOLLATE
を安全なSQL文字列として使えるようになった
参考: PostgreSQL 15ドキュメント 24.2. 照合順序サポート
参考: MySQL :: MySQL 8.0 リファレンスマニュアル :: 10.8.1 SQL ステートメントでの COLLATE の使用
データベース用rakeタスクのVERSION
引数でアンダースコア(_
)も使えるようになった。
Eddie Lebow
同CHANGELOGより
参考: 週刊Railsウォッチ20220221: DBのrakeタスクでVERSION
envの数値に_
が使えるようになった
structure.sql
ダンプのINSERT
ステートメントで値の並び順を逆にした。
これにより、マージで競合する可能性が減るはず。
新しいマイグレーションでは、新しい値がリストのトップに追加されるようになる。
ただし、既存のアプリでは次回structure.sql
を生成したときに大量の差分が発生することになる。
Alex Ghiculescu, Matt Larraz
同CHANGELOGより
Ruby 2.7とActive Record 6.1.4でPG.connect
にキーワード引数を渡すと非推奨警告が表示されていたのを修正。
修正: #44307
Nikita Vasilevsky
同CHANGELOGより
この修正は、Rails 7.0.2でリリース済みです。
関連: [Tests only] Flunk if test is not using SavepointTransaction by nvasilevski · Pull Request #44686 · rails/rails
シリアライズが失敗してデッドロックした後でデータベースコネクションが切断されるバグを修正。
6.1.4より前は、シリアライズが失敗してデッドロックすると、実際のトランザクションとsavepointの両方でロールバックが発行されていた。MySQLはデッドロック後にsavepointのロールバックを許さないため、これによって壊れてしまう。
6.1.4では実際のトランザクションとsavepointの両方でロールバックが削除されたが、これによってデータベースコネクションのステートがunknownになり、切断されてしまう。
この修正によって、MySQLのsavepointを除いてロールバックが復元されるようになった。
Thomas Morgan
同CHANGELOGより
参考: MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.3.4 SAVEPOINT、ROLLBACK TO SAVEPOINT および RELEASE SAVEPOINT ステートメント
ActiveRecord::ConnectionPool
がFiberセーフになった。
ActiveSupport::IsolatedExecutionState.isolation_level
で:fiber
を指定すると、コネクションプールからコネクションをチェックアウトする同一のThreadからの複数のFiberをサポートするようになる。
Alex Matchneer
同CHANGELOGより
Rails 7: Active RecordのConnectionPoolsがFiberセーフになった(翻訳)
ActiveRecord::Persistence
にupdate_attribute!
を追加。
update_attribute
と同様だが、before_*
コールバックで:abort
がスローされた場合はActiveRecord::RecordNotSaved
をraiseする点が異なる。
class Topic < ActiveRecord::Base
before_save :check_title
def check_title
throw(:abort) if title == "abort"
end
end
topic = Topic.create(title: "Test Title")
# #=> #<Topic title: "Test Title">
topic.update_attribute!(:title, "Another Title")
# #=> #<Topic title: "Another Title">
topic.update_attribute!(:title, "abort")
# raises ActiveRecord::RecordNotSaved
Drew Tempelmeyer
同CHANGELOGより
参考: Rails API update_attribute
-- ActiveRecord::Persistence
参考: 週刊Railsウォッチ20220117: update_attribute!
が追加
ActiveRecord::Relation
の#pretty_print
で全レコードの読み込みを回避するようになった。
# 修正前
pp Foo.all # 全テーブルを読み込む
# 修正後
pp Foo.all # 10件まで表示し、残りを"..."で表示
Ulysse Buonomo
同CHANGELOGより
参考: 週刊Railsウォッチ20220117: Relation#pretty_print
のeager loadingを回避
QueryMethods
の#in_order_of
メソッドで、指定の値にないレコードをWHERE
で除外するように変更。
Enumerable
のin_order_of
と振る舞いを合わせるため、QueryMethods
のin_order_of
に渡した値のリストで絞り込んだものを並べ替えるようにした。
Kevin Newton
同CHANGELOGより
# 同PRのAPIドキュメントより
User.in_order_of(:id, [1, 5, 3])
# SELECT "users".* FROM "users"
# ORDER BY FIELD("users"."id", 1, 5, 3)
# WHERE "users"."id" IN (1, 5, 3)
注: このプルリクによって、#43916の「指定外のレコードのソート順も維持する振る舞い」が打ち消されました。
参考: この改修はRails 7.0.1でリリース済みです。
Rails 7: クエリ結果を任意の順序にできるActiveRecord::QueryMethods#in_order_of
名前付きの式インデックスをロールバックできるよう修正。
従来は、リバーシブル(取り消し可能)なマイグレーションのロールバックで以下のコードがエラーになった(インデックスの削除でこのインデックス名が使われていなかったため)。
add_index(:settings, "(data->'property')", using: :gin, name: :index_settings_data_property)
修正: #43331
Oliver Günther
同CHANGELOGより
PostgreSQLのstructure dumpタスクのヘルプ説明文にある引数名のスペルを修正。
Rails 7で追加された--no-comment
引数を正しい--no-comments
(複数形)に更新した。
Alex Dent
同CHANGELOGより
マイグレーションのバージョンが6.0の場合に、SQLite3のreferences
カラムとbelongs_to
カラムがinteger
型として作成されるよう修正。
バージョン6.0のreferences
カラムとbelongs_to
カラムが、SQLite3のアダプタでinteger
型ではなくbigint
型で作成されていた。
Marcelo Lauxen
同CHANGELOGより
この修正は、Rails 6.1.5でリリース済みです
QueryMethods
の#in_order_of
に空のリストを渡せるよう修正。
Post.in_order_of(:id, []).to_a
また、このカラムを明示的に第2ソート順として設定することで、指定以外の値のソート順を維持するようになった。
Jean Boussier
同CHANGELOGより
注: 指定以外の値のソート順を維持する振る舞いは、その後#44097でなくなりました。
この改修は、Rails 7.0.1でリリース済みです。
Rails 7: クエリ結果を任意の順序にできるActiveRecord::QueryMethods#in_order_of
計算系メソッドによって生成されるカラムエイリアスを正しく引用符で囲むよう修正。
このエイリアスはテーブル名から導出されるので、有効な識別子を得られるという前提が成り立つとは限らない(テーブル名が数字始まりの場合など)。
class Test < ActiveRecord::Base
self.table_name = '1abc'
end
Test.group(:id).count
# syntax error at or near "1" (ActiveRecord::StatementInvalid)
# LINE 1: SELECT COUNT(*) AS count_all, "1abc"."id" AS 1abc_id FROM "1...
Jean Boussier
同CHANGELOGより
has_secure_password
にauthenticate_by
メソッドを追加。
このauthenticate_by
メソッドは、以下のようなコードを置き換えるのが目的。このコードは、メールアドレスが一致するユーザーが見つからない場合に、見つかった場合よりも早期に処理が終了してしまう。
User.find_by(email: "...")&.authenticate("...")
このようなコードは、タイミングベースの列挙攻撃に対して脆弱である。攻撃者はこの脆弱性を使って、特定のメールアドレスを持つユーザーアカウントが存在するかどうかを検索時間の違いで判定可能になる。アカウントが存在することを攻撃者が確認できたら、他のデータベースから漏洩したパスワードの中から、そのメールアドレスに関連付けられたパスワードを試せるようになる。これは、ユーザーが同じパスワードを複数のサイトで使い回すというありがちな運用で起こる可能性がある。さらに、攻撃者がアカウントのメールアドレスを手に入れれば標的型フィッシング("spear phishing")攻撃を試みることも可能になる。
authenticate_by
は、メールアドレスが一致するユーザーが見つかった場合にかかる時間と、一致するユーザーが見つからない場合にかかる時間を同じにすることで、この脆弱性を修正する。
User.authenticate_by(email: "...", password: "...")
Jonathan Hefner
注: その後、パスワードが空の場合の修正も7.1.0.beta1に含まれました。
Short circuit authenticate_by
on empty password by jonathanhefner · Pull Request #43958 · rails/rails
Rails 7: has_secure_password利用時のauthenticate_byメソッド(翻訳)
以前の変更については7-0-stableのCHANGELOGを参照。
関連記事
Rails 7.1に入る主要な機能まとめ(1)update_attribute!、CTEサポートほか(翻訳)
Rails 7.1に入る主要な機能まとめ(2)error_highlight対応、routes --grepほか(翻訳)
Rails 7.1に入る主要な機能まとめ(3)Docker関連ファイル導入ほか(翻訳)
The post Rails 7.1.0 Active Record CHANGELOG(翻訳) first appeared on TechRacho.
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
参考: 週刊Railsウォッチ20220328
where.first
とfind_by