ここでは、Rails 5.2で導入されたActiveModel::Attributesについて紹介します。RubyのクラスにActiveRecordのカラムのような属性を加えられます。
サンプル:
https://github.com/kazubon/blog-rails6-vuejs/blob/master/app/forms/entries/form.rb
クラスにActiveModel::ModelとともにActiveModel::Attributesをインクルードします。
class Entries::Form
include ActiveModel::Model
include ActiveModel::Attributes
クラスメソッドattributeに属性名と型を渡すと、attr_accessorと同じように属性が使えるようになります。指定できる型の種類については、Railsのソースを直接参照してください。
attributeをクラスの冒頭に並べておくと、「このクラスは何をパラメータとして受け取るのか」を明示できるというメリットもあります。なお、この例のtagsは配列で、指定できる型がないので型を指定していません。
attribute :title, :string
attribute :body, :string
attribute :draft, :boolean, default: false
attribute :published_at, :datetime
attribute :tags
defaultオプションで初期値を指定できます。Procも指定できます。
attribute :published_at, :datetime, default: ->{ Time.now }
属性を使うには、superでActiveModel::Attributesのinitializeメソッドを呼び出す必要があります。
def initialize(user, entry, params = {})
@user = user
@entry = entry
super(params)
end
このsuper(params)
は次のように置き換えても同じです。
@attributes = self.class._default_attributes.deep_dup
assign_attributes(params)
ActiveRecordのカラムと同じく、attributeで加えた属性に値を入れると、数値、時刻、ブーリアンのような型に合わせて値が変換されます。時刻(:datetime)では次のような感じです。
form.published_at = "2019/12/19 12:30"
form.published_at #=> 2019-12-19 12:30:00 +0900
form.published_at = "xxxxx"
form.published_at #=> nil
ブーリアン(:boolean)では、[false, 0, "0", :"0", "f", :f, "F", :F, "false", :false, "FALSE", :FALSE, "off", :off, "OFF", :OFF]
が false、それ以外は true になります。空文字列はnilになります。
form.draft = "1"
form.draft #=> true
form.draft = "0"
form.draft #=> false
インスタンスメソッドattributesで「属性名 => 値」のハッシュが取り出せます。
form.attributes
#=> {"title"=>"Foo", "body"=>"bar", "draft"=>false, "published_at"=>2019-12-15 15:40:00 +0900, "tags"=>["Ruby", "Rails"]}
インスタンスメソッドまたはクラスメソッドのattribute_namesで属性一覧が取り出せます(Rails 6で追加)。
form.attribute_names
#=> ["title", "body", "draft", "published_at", "tags"]
以上です。
ActiveModel::Attributes を使わずに型キャストをしたいときは、 ActiveRecord以外で型キャストを使う を参照しくてください。