概要
Formオブジェクトなどを実装する場合、ActiveModel::Model
をincludeしたPOROクラスを実装することがあると思います。
この記事ではその際に、追加のmoduleを使ってできることをまとめてみました。
環境
Rails: 7.0.3
ActiveModel::API
まずはこのActiveModel::API
をincludeすることから始まります。
これにより、以下のような機能が利用できます。
-
form_with
やrender
などのAction Viewのヘルパーメソッド - 値のvalidation
tips
- 値を上書きしたい場合、対象のattributeは
attr_reader
にしておき、#{attr_name}=
のsetterを定義します。
email_contact.rb
class EmailContact
include ActiveModel::Model
# 値を変更したい場合、ここはattr_readerだけにして、setterメソッドを定義する
attr_accessor :email
attr_reader :message
validates :email, :message, presence: true
# setter
def message=(value)
@message = value + 'ありがとうございます。'
end
def deliver
if valid?
# deliver email
end
end
end
new.html
<%= form_with model: @email_contact, local: true do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :message %>
<%= f.text_area :message %>
<%= f.submit %>
<% end %>
email_contacts_controller.rb
class EmailContactsController < ApplicationController
def create
@email_contact = EmailContact.new(email_contact_params)
# <@email="sample@example.com", @message="こんにちはありがとうございます。">
@email_contact.deliver
end
def new
@email_contact = EmailContact.new
end
def email_contact_params
params.require(:email_contact).permit(:email, :message)
end
end
ActiveModel::Attributes
ActiveModel::Attributesを使うことで、以下のような機能が利用できます。
- 値のキャスト
- 値のデフォルト値設定
tips
- キャストは自分自身でキャスト方法を定めたtypeを定義することが可能です。(以下の
Creating Custom Types
参照)
https://edgeapi.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute
email_contact.rb
class EmailContact
include ActiveModel::Model
include ActiveModel::Attributes
# formに何も入れなかった場合、sample@example.comが入る
attribute :email, :string, default: 'sample@example.com'
# formからは文字列のparamsが渡ってくるが、これによりdate型に変換される
attribute :send_date, :date
...
end
new.html
<%= form_with model: @email_contact, local: true do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
...
<%= f.label :send_date %>
<%= f.date_field :send_date %>
<%= f.submit %>
<% end %>
以下のように、デフォルト値の設定と、キャストが行われます。
また、attributes
などのメソッドも利用できるようになります。
email_contacts_controller.rb
class EmailContactsController < ApplicationController
def create
@email_contact = EmailContact.new(email_contact_params)
# @email.contact.attributes => {"email"=>"sample@example.com", "send_date"=>Sat, 01 Jan 2022}
@email_contact.deliver
end
...
end
Enumerize
列挙型を扱う際に使いますが、こちらも組み込むことが可能です。
これにより、以下の機能などが利用可能です。
- 値のValidation
- Form側でのoptionsの使用
- i18nの設定
tips
- enumerizeを定義したattributeは、以下で定義されるため
attributeメソッド
を使う必要はありません。
https://github.com/brainspec/enumerize/blob/master/lib/enumerize/attribute.rb#L90-L121
class EmailContact
include ActiveModel::Model
include ActiveModel::Attributes
extend Enumerize
enumerize :type, in: %w(purchase notice register)
attribute :email, :string
validates :name, :email, :message, presence: true
...
end
以下のようにEmailContact.type.options
でオプション一覧を表示可能。
keyはtype.text
になるので、i18nを使用すれば、その値で表示される。
new.html
<%= form_with model: @email_contact, local: true do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
...
<%= f.label :type %>
<%= f.select :type, EmailContact.type.options %>
<%= f.submit %>
<% end %>
email_contacts_controller.rb
class EmailContactsController < ApplicationController
def create
@email_contact = EmailContact.new(email_contact_params)
# @email.contact.attributes => {"type"=>"purchase", "email"=>"sample@example.com"}
@email_contact.deliver
end
...
end