Edited at

ActiveModel::Attributes が最高すぎるんだよな。

More than 1 year has passed since last update.

Ruby on Rails 5.2.0.beta2が出て久しい。

僕はRails大好きっ子なので

社内の新規事業や、社外のお手伝いしているベンチャー企業では

もちろん、Rails5.2を使って開発をしている。

すでに、新しいRailsに関する記事はいくつか挙がっているが

個人的に、一番インパクトが大きかったのはActiveModel::Attributesが導入されたことである。


:yellow_heart: 待望のActiveModel::Attributes :yellow_heart:

ActiveModel::Attributesでなにが変わったの?というと、

いままでActiveRecordでしか使えなかった一部の機能が、ActiveModelでも使えるようになっただけである。

いや、しかし!

今までのActiveModelの最大の弱点は

まさにこの ActiveModel::Attributes が無かったことだと思う。

それが、Rails5.2で使えるようになったのだ。

こんな嬉しいことはない。


みんな大好き .attribute

Rails5.1系でも使えた.attributeを改めてみてみよう

ActiveRecordには、Attribute APIというインターフェース(?)があり、

型情報の変換は、あまり考えることなく透過的に扱うことができる。

class User < ApplicationRecord; end

id = '1' # 文字列
user = User.new(id: '1')
user.id #=> 1 数値に変換されている

そして、この型変換は定義を上書きすることもできる

class User < ApplicationRecord

attribute :time_zone, :string, default: -> { Time.zone.name }
attribute :confirmed, :boolean, default: false
end

user = User.new
user.time_zone == Time.zone.name #=> true
user.confirmed == false #=> true

独自の型変換もOKなので、 Money などのクラスを定義して型変換を行わせることもできる。

カラムがなくてもOKなので、attr_accesorの代わりに使える。

すこぶる便利である。

しかし、ActiveRecordでしか使えないのである。


さて、ActiveModelの話ですよ。

7 Patterns to Refactor Fat ActiveRecord Models を通じてか

多くのプロジェクトでFormObjectServiceObject(っぽいもの)を見る機会が増えた。

みんなFormObjectをActiveModelで定義するのだが

その型変換には定まった方法が無かった。

class RegistrationForm

include ActiveModel::Model

attr_accessor :accepted
end

RegistrationForm.new(xxx_params).accepted #=> 型はなに??

そして、その解決策は人によって様々で

これといった最善策は無かった。

class RegistrationForm

include ActiveModel::Model

attr_reader :accepted

# まともな変換
def accepted=(value)
@accepted = ActiveModel::Type.lookup(:boolean).cast(value)
end

# なんてこった...
def accepted=(value)
@accepted = value == '1'
end
end

そもそも、記述量も多いしイケテナイ感がありました。


ほら、ここでActiveModel::Attributesですよ。

ようやく、秩序が保たれる時代になりました。

.attributeがActiveModelでも使えるようになったのです。

class RegistrationForm

include ActiveModel::Model
include ActiveModel::Attributes

attribute :accepted, :boolean, default: false
end

もうね、大興奮です。

めっちゃシンプル。

誰でも同じ書き方になる。

AttributeMethodsも使える...。

ありがてぇ。ありがてぇよ。


Rails5.1だとまだ使えない

使えないんです、そうなんです。

社内の人と話していて、他のプロジェクトでも.attribute使いたいーって話があったので

それっぽいものを使えるようにしました。

# 来週ぐらいにはruby gemsに出そうかな 同じ名前ですでにgemが存在したため、gem pushできず...!みんな同じようなこと考えるのね。。

https://github.com/alpaca-tc/active_model_attributes

gem 'active_model_attributes', github: 'alpaca-tc/active_model_attributes'

class YourModel

include ActiveModel::Model
include ActiveModelAttributes # Rails5.2になったら、ActiveModel::Attributesに置き換えるだけ。

attribute :accepted, :boolean, default: false
end

これで、日々の開発が少し幸せになりそうです。

毎年、とても興奮するアップデートをいれてくださるRailsコミュニティには

本当に感謝しています。