Hashie::Dashでお手軽validationあるいはリソースを信用できるかどうか問題
intridea/hashie: Hashie is a collection of classes and mixins that make hashes more powerful.
まとめ
- Ruby で nil を避ける方法は事前に validate する方法と取得時、利用時に気をつける方法がある
- 事前に validate できる方が安心だしテストも楽(影響範囲が小さい)
- いくつか validator はあるが Hashie::Dash は validate 機能内蔵していてかなりお手軽でいい感じ
- 独立した validator を使うのは大袈裟だなと感じるようなカジュアルなシーンにハマりそう
Rubyでnilを避ける方法百選
nil が入るかもしれないところのコードをどうするかにはいくつか方法がある。
- ActiveSupport の try
- ぼっち演算子 (&. )
- 文字列と分かっているなら .to_s
- 逆に Hash から取り出す時に死んでほしい Hash#fetch
- 素朴に nil?
などなど。
逆に DBMS 前提なら例えば ActiveRecord で
create_table do |t|
t.string :name, null: false
end
とすると name に nil を入れて save することはできない。
ま、扱うオブジェクトによっていろいろある。
事前に弾くのか、取得時に考慮するのか
上に挙げた例はアプローチが正反対である。
- 前者は値の取得時、利用する際に nil を避ける方法
- 後者はそもそも nil が入らないようにする方法
今回は後者の nil が入らないようにするということを validation と呼ぶことにしている。
Hashie::Dashの使い方
Hashie::Dash はみんな大好き Hashie::Mash に事前の property 定義が書けるもの。以下のような感じ。
class Model < Hashie::Dash
property :foo, required: true
end
これで
Model.new(foo: nil)
とすると
ArgumentError: The property 'foo' is required for Model.
というエラーになる。おぉ、これならふいに nil を踏むことはなくなるじゃん。逆に
Model.new(foo: 'nil', bar: 1)
になると
NoMethodError: The property 'bar' is not defined for Model.
で、余計な property を突っ込むこともできない。
m = Model.new(foo: 'nil')
m.bar = 1
だと
NoMethodError: undefined method `bar=' for #<Model foo="nil">
おおおお。初期化時だろうと動的な変更だろうと弾いてくれる。
ということで Dash は以下のようなものらしい。
- Hashie::Dash は事前に property を定義することができる Mash のようなもの
- property の validation が自動で行われる
- required: true の property は必須でかつ nil を与えることはできない
- 余計な property を追加することもできない
intridea/hashie: Hashie is a collection of classes and mixins that make hashes more powerful.
の例を見ると他の property を参照することもできる。けっこう便利。
まぁ Rails 使ってるなら ActiveModel できっちり固めるという方法もあると思うし、Hanami みたいに dry-validation で schema を書くという方法もあると思うけど、もっとカジュアルに使いたいよねって時に Hashie::Dash で validate しておくと、単なる Hash より
- いい具合にオブジェクトっぽく振舞ってくれる
- 事前の定義で比較的安全に扱えるようにできる
ということが分かった。
なるほどな。