Sequel::Model におけるしなやかな validation

Ramazeさんと相性抜群な感じのORM(としても使える)ライブラリ Sequel は、Sequel::Model が Rails や DataMapper 的にモデルを定義できちゃったりしてもうとっても楽チンなわけです。しかし残念なことに現状 validation に関しては極めてイマイチではないかと思います。

Sequel::Model における validation は Rails流の validation を実現する Assistance というライブラリを採用しています。しかしこの Assistance が微妙、バージョンナンバーも 0.1.4 (2008-02-08) という感じでまだまだ熟成していないせいでしょうか、なんだか使い勝手が悪いというか予め決められた種類の validation しか出来ないので柔軟さに欠きます(ホントは出来なくはないのですが、極めて面倒っちいので嫌です)。そう思うなら Assistance にパッチ投げればいいじゃないの!というわけなんですが、とりあえず今回は Assistance に頼らない方法を書き残しておきます。

しなやかというか粗野な validation 方法

まず、sequel_model/validations.rb (sequel_model-0.4.1) は次のようになっております。

gem "assistance", ">= 0.1.2" # because we need Validations

require "assistance"

module Sequel
  class Model
    include Validation
    
    alias_method :save!, :save
    def save(*args)
      return false unless valid?
      save!(*args)
    end
  end
end

てなわけだから、valid? を呼び出して、真偽値を返せば良いわけです。だので、次のようにして valid? を定義しましょう。

class Model < Sequel::Model
  def valid?
    ... # ここに条件をずらずらと書く、良いなら真を、ダメなら偽を返すこと
  end
end

とっても簡単!というか、Sequel::Model は validator ライブラリを自由に選択可能にすべきだと思う(現状Assistance以外に存在を知りませんが)。これもなんとかしたいところです。(追記:NotNaughtyというのがあります、もう既に選択可能になっているようです)

ついでに Assistance で柔軟に

一応 validates_each を使えば極めて柔軟にやれます。

class Model < Sequel::Model
  validates_each :col do |obj, attr, val|
    obj.errors[attr] << 'はダメなんだってさ!' unless val.is_valid?
  end
end

みたいな感じで書くと良さそうです。でも validates_each の each がすごく気になったり、その面倒そうなブロック引数はなに?とか思うわけです。これを粗野に書くとさらに次のようになります。

class Model < Sequel::Model
  validations[:col] << proc {|obj, attr, val|
    obj.errors[''] << 'が発情期で困ってます' unless val.is_valid?
  end
end

とりあえず each は消えましたが、多分こうやって使われることは意図していないものと思われます。あとAssistanceはエラーメッセージの国際化とか考えてないからやっぱり困ると思います。なんとかしたいものです。

追記

validationライブラリはAssistanceしかないのかと思ったら、NotNaughtyってのがあるんだって!しかもSequelでも使えますというか、Seqeulで使われることを主眼に置いているような感じです(ちゃんとSequel::Pluginも用意されていて、簡単に使えます)。というわけで近日中にNotNaughtyを試してみたいと思います。