ActiveModelとは?
非ActiveRecordのソースを複雑にしているデータや処理のまとまりを見つけてそれをクラスにする等の機能のことです。
ActiveModelの代表的なサブモジュール
ActiveModelはいくつかのサブモジュールから構成されます。
モジュール名 | 機能 |
---|---|
AttributeAssignment | attr_accessor等で定義した属性値へのアクセサメソッドに対してHashで値を割り当てる「assign_attributes」メソッドを定義する。 |
Naming | モデル名を便利に扱う「model_name」クラスメソッドを定義する。これから得られるオブジェクトに対してRailsはi18nやrouting等の類推を行う。 |
Conversion | オブジェクト情報からURLパラメータ生成やパーシャルパスの解決ができる。 |
Translation | 「human_attribute_name」メソッドを通じてi18nによる変換を利用できるようにする。この機能を使ってフォームヘルパーは自動で属性名を変換したりする。 |
Validations | バリデーションやバリデーションオブジェクトの「errors」メソッドを扱えるようにする。 |
フォームオブジェクトとは?
「非ActiveRecordモデル」のインスタンスです。form_withメソッドのmodelオプションに紐づけることができます。
用途
「データベースとは無関係なフォーム」や「データベースのテーブルと1:1に紐づいていないフォーム」をform_withメソッドで生成することができます。
作成ディレクトリ
Railsプロジェクトの下記のディレクトリで作成する場合が多いです。
1 |
app/forms |
実際の業務では、さらにサブディレクトリを作成して「名前空間::xxxForm」というフォームオブジェクトのクラス指定をしていることも多いです。
実装方法
フォームオブジェクトの作成方法
1 2 3 4 5 |
class 名前空間(ディレクトリに切っていた場合)::xxxForm include ActiveModel::Model attr_accessor :フォームのフィールド名1, :フォームのフィールド名2 end |
ポイントとしては下記の2点です。これを守ればform_withのmodelで使用することです。
- ActiveModel::Modelをincludeすること
- ActiveRecord::Baseクラスを継承しないこと
attr_accessorで指定したフィールドはform_with内で使用できるフィールド名になります。
呼び出し方
コントローラで下記のようにフォームオブジェクトを変数に格納します。
1 |
@form = 名前空間名::フォームオブジェクト名.new |
ビュー側では下記のように指定します。
1 2 3 |
<%= form_with model: @form, url: :パス do |f| %> ‥ <% end %> |
EachValidator
「ActiveModel::EachValidator」を使えば、バリデーション用のクラスを作ることができます。
呼び出し元
lib/validator/email_validator.rb
1 2 3 4 5 |
class EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) record.errors.add(attribute, :too_long, count: max) if value.length > 100 end end |
emailのバリデーターであれば上記のように「EmailValidater」というクラス名にします。emailという名前で呼び出すことが可能になります。
validate_eachメソッド
byebugを仕込んで、モデル名.createメソッドを実行すれば中身を確認することができます。
record
これから登録しようとするモデルのオブジェクトが入っています。
1 |
errors.add(属性,エラーメッセージ) |
attribute
属性が入っています。
value
登録しようとしている値が入っています。
呼び出し先
Railsのオートローダーの「Zeitwerk」ではlibディレクトリ配下は自動でロードしてくれないのでrequireで明示的に呼び出す必要があります。
1 2 3 4 5 |
require "validator/email_validator" class User < ApplicationRecord validates :email end |
単一テーブル継承(STI)とは?
オブジェクト指向の継承をRDBMSで疑似的に実現する方法です。Railsではtypeカラムにクラス名を記録することで実現することが可能です。
実装方法
modelのクラスを下記のように親クラスと子クラスでそれぞれ作成して子クラスには親クラスを継承させます。
1 2 3 4 5 6 7 8 |
class 親クラス < ApplicationRecord end class 子クラス1 < 親クラス end class 子クラス2 < 親クラス end |
保存
Railsのプログラム内で下記のように保存処理を記述します。
1 2 |
子クラス1.create(親クラスの列: "1001") 子クラス2.create(親クラスの列: "1003") |
実際にテーブルに格納されるレコードは下記のようになります。typeカラムはRailsが自動的に設定してくれます。
id | type | レコード名 |
---|---|---|
1 | 子クラス1 | 1001 |
2 | 子クラス2 | 1003 |
取得
下記のように取得します。なお、サブクラス1に対応するレコードがなければレコードが見つからないというエラーになってしまうので注意です。
1 2 |
サブクラス1.find(1) サブクラス2.find(2) |
この記事へのコメントはありません。