LoginSignup
12
11

More than 5 years have passed since last update.

singleton_classを使ってActiveRecordのvalidatorをオブジェクトに追加する

Last updated at Posted at 2016-02-23

Railsでアプリを作ると、必ず困ることの一つにActiveRecordのvalidatorがあります。

一般のユーザ登録の時はnameが必須だけど、管理画面からはなくても登録できるようにしたい、というケースが良くあります。

その場合、validates :name, presence: true, if: :require_name? という風にifオプションで対応することになります。

しかし、すべてのvalidatesにこれを追加するのはちょっと違うなぁとも思います。

validatesscopeオプションを追加して、save_with(:name)みたいメソッドを定義し、そこで使うvalidatorを選択すればいいかなとか考えましたが、もっとシンプルにobjectにvalidatorをmix-inで追加できるようにしてみました。

Ruby 1.9.2からあるObject#singleton_classを使うと下記のようにしてオブジェクトにvalidatorを追加できます。

user = User.new
user.singleton_class.class_eval do
  validates :name, presence: true
end

これをcontrollerに書くのはダメなので、moduleにして読み込めるようにする、object_extender gemを作ってみました。

require 'object_extender'
class User < ActiveRecord::Base; end

module RequireName
  extend ObjectExtender
  extended_class do
    validates :name, presence: true
  end
end

me = User.new(params)
me.save! # OK

# nameを必須にする
me.extend(RequireName)
me.save! # Failed

このように使うシーンに合わせてvalidatesを追加したり、データの正規化を行うためにbefore_validationを追加することができます。

Railsで使うときは、app/models/user/require_name.rbmodule User::RequireNameという形で置けばいいかなーと思っています。

週末に思いつきでお風呂で作ったので、コメントをお待ちしています。

ソースは短くて、30行程度です。
https://github.com/masuidrive/object_extender_rb/blob/develop/lib/object_extender.rb

こういう問題をスマートに解決する方法を一緒に考えてくれる人いないかなぁということで、考えてくれる人は、3,000万人の予約を支えるRailsエンジニア募集!でお待ちしています。

よければ、トレタメンバーのQiitaも見ていって下さい。

12
11
0

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
12
11