protected_environmentsをActiveRecordモジュールに移動
protected_environments の設定が ActiveRecord::Base から ActiveRecord モジュールのトップレベルに移動され、グローバル設定として管理されるようになりました。この変更により、設定の意図がコードに明示され、class_attribute の継承機能が実質的に使われていなかった実装上の矛盾が解消されます。
背景
protected_environments は、本番環境など破壊的な操作を禁止すべき環境を指定する設定です。900bfd9 で class_attribute として実装され、後に 1a411d4 で class_attribute を使わない実装に変更されましたが、class_attribute のような継承動作は維持されていました。
しかし、データベースタスク内での実際の利用は常に ActiveRecord::Base.protected_environments を参照しており、継承による個別のサブクラス設定は活用されていませんでした。設定は実質的にグローバルとして扱われていたにもかかわらず、クラス属性として定義されていたことが実装上の矛盾となっていました。
技術的な変更
activerecord/lib/active_record.rb に protected_environments の定義が追加され、モジュールレベルのシングルトンメソッドとして実装されました。
変更後の実装:
singleton_class.attr_reader :protected_environments
def self.protected_environments=(environments)
@protected_environments = environments.map(&:to_s)
end
self.protected_environments = ["production"]
データベースタスクでの参照先も ActiveRecord.protected_environments に変更されています。
activerecord/lib/active_record/migration.rb:
def protected_environment?
ActiveRecord.protected_environments.include?(last_stored_environment) if last_stored_environment
end
ActiveRecord::Base の既存のメソッドは非推奨として残され、ActiveRecord モジュールの設定にプロキシする実装になりました。
activerecord/lib/active_record/model_schema.rb:
def protected_environments
ActiveRecord.deprecator.warn <<~MSG
ActiveRecord::Base.protected_environments is deprecated in favor of
ActiveRecord.protected_environments and will be removed in Rails 9.0.
MSG
if self == ActiveRecord::Base
ActiveRecord.protected_environments
elsif defined?(@protected_environments)
@protected_environments
else
superclass.protected_environments
end
end
ActiveRecord::Base で呼び出された場合はモジュールレベルの設定を返し、サブクラスで呼び出された場合は従来の継承動作を維持します。セッターも同様に、ActiveRecord::Base への代入はモジュールレベルの設定を変更し、サブクラスへの代入は個別のインスタンス変数を設定します。
設計判断
グローバル設定への移行と後方互換性の両立 が設計の中心です。
設定の実体をモジュールレベルに移動しながら、既存の ActiveRecord::Base.protected_environments によるアクセスを非推奨警告付きで維持しています。Rails 9.0 での削除を予告することで、段階的な移行期間を設けています。
サブクラスでの個別設定は引き続き動作しますが、データベースタスクがグローバル設定のみを参照する以上、サブクラスごとの設定は実質的な意味を持ちません。この判断により、設定の意図と実装が一致し、利用者が設定の影響範囲を正しく理解できるようになります。
まとめ
本PRは、設定の実装場所をその実際の用途に合わせて移動した変更です。class_attribute のような継承動作を持ちながら、グローバル設定としてのみ利用されていた矛盾を解消し、設定の意図をコードに明示しています。既存のAPIは非推奨として維持されており、Rails 9.0 までの移行期間が確保されています。