487
312

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-01-18

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コミュニティには
本当に感謝しています。

487
312
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
487
312