Rails 7: Active ModelからActiveModel::APIが切り出された(翻訳)
私たちはRailsで作業するときにActive Recordに慣れ親しんでいます。Active RecordはMVCフレームワークにおけるモデルであり、システムでビジネスデータやビジネスロジックの表現を担当する層です。Active Recordは、アプリケーション内のリッチなオブジェクトをRDBMS上のテーブルに接続するORM(Object-relational mapping)でもあります。
Railsで、データベース内のどのテーブルとも紐付けられていない普通のクラスが、モデルのような機能を必要とすることがあります。こういうときはRailsのActive Modelの出番です。Active Modelは、Active Recordの機能の一部を必要とするクラスを開発するときに使われるライブラリです。
たとえばname
属性とid
属性を持つPerson
クラスがあるとします。これらの属性をバリデーションする機能を追加したい場合は、 ActiveModel
を使うことで以下のようにPerson
クラスを実装できます。
class Person
include ActiveModel::Model
attr_accessor :name, :email
validates :name, :email, presence: true
end
irb> person = Person.new(name: "Sam", email: "sam@example.com")
irb> person.name
# => "Sam"
irb> person.email
# => "sam@example.com"
irb> person.valid?
# => true
irb> person.persisted?
# => false
ActiveModel::Model
をinclude
すれば、以下のような機能も使えるようになります。
- モデル名を調べる
ActiveModel::Conversion
(変換)ActiveModel::Translation
(翻訳)ActiveModel::Validator
(バリデーション)
ActiveModel::Model
をinclude
したクラスでは、Active Recordオブジェクトと同じようにform_with
やrender
などのAction Viewヘルパーメソッドが使えるようになります。
変更前
Rails 7より前のActiveModel::Model
は、Action PackやAction Viewとやりとりする最小限のAPIとして動作します。
「Model」という名前から分かるように、ActiveModel::Model
をinclude
すればActive Recordのようなモデルを作成できます。しかしActiveModel::Model
では、基本的なActiveModel::Attributes
機能がサポートされていませんでした。
attribute
メソッドを使おうとして失敗する様子をちょっと見てみましょう。
class Person
include ActiveModel::Model
attribute :name, :string
attribute :email, :string
end
NoMethodError (undefined method `attribute' for Person:Class)
これを解決するには、Person
クラスにActiveModel::Attributes
をinclude
する必要があります。
変更後
Rails 7以降は、ActiveModel::Model
の実装がActiveModel::API
に移動します(#43223)。
ActiveModel::API
がAction PackやAction Viewとやりとりするときの定義は最小限に抑えられています。これにより、ActiveModel::Model
は、今後Active Recordのモデルのような機能を追加して拡張できます。
注
ActiveModel::Model
はActiveModel::API
だけをinclude
するようになりました。このおかげで、後方互換性を維持しながらモデルに機能を追加できるようになりました。
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
参考: 週刊Railsウォッチ20210921 ActiveModel::APIが追加