3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Railsのvalidatesの引数に名前を付けて共通化する

Posted at

概要

class CommonValidations < NamedValidations
  define :required, :presence, true
  define :short_text, :length, maximum: 100
  define :long_text, :length, maximum: 5_000
  define :formatted_text, :format,
    with: /\A(?:[^:[:space:]]+:[^\n]*(\n\s+[^\n]*)*\n)*\z/,
    allow_blank: true
  define :formatted_long_text do |*_args|
    long_text.formatted_long_text
  end
end

class Article < ApplicationRecord
  base = CommonValidations.new
  validates :title, base.short_text.required
  validates :content, base.long_text(minmum: 100)
  validates :meta, base.formatted_long_text
end

説明

Railsのvalidatesの引数に同じような指定がならぶことがあります。もともとの要件が共通なら、コードのほうでも共通にしたい。いろいろなやり方がありそうですが、その一つとして引数のならびに名前を付けられるようにする、というのを作ってみました。

validates :foo, length: { maximum: 100 }, presence: true, ...
#               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#               この部分に名付けする

これはvalidatesの引数を定数にするのに似ています。

VALIDATIONS_HOGE = { length: { maximum: 100 }, presence: true, ... }
validates :foo, VALIDATIONS_HOGE

定数を使った場合、指定内容を少しだけ変えたいときに工夫が必要です。

# ここだけ maximum: 99 にしたい
validates :bar, VALIDATIONS_HOGE.deep_merge(length: { maximum: 99 })

一度きりならともかく、二つ、三つとなると「少しだけ変えたい」だけのわりには記述量が多く、定数にまとめた意味が半減してしいます。

そこで、定数とは別の形で名前を付けることで、部分的な上書き指定をできるようにしてみました。

たとえば上の例のVALIDATIONS_HOGEにあたる内容にvalidations_hogeと名付けると、次のように記述できます。

validates :foo, validations_hoge
validates :bar, validations_hoge(maximum: 99)

この例での名付けは以下のように行います。

class CommonValidations < NamedValidations
  define :validations_hoge do |*opts|
    length({ maximum: 99 }, *opts).presence(true)
  end
end

付けた名前を使用するには以下のようにします。

v = CommonValidations.new
validations_hoge = v.validations_hoge
validates :foo, validations_hoge

validations_hogeにその場で指定を追加することもできます。

v1 = validations_hoge.format(with: /@/)
v2 = v1.length(minimum: 5)

validates :bar, v1
validates :baz, v2.presence(if: ...)

使用例

concerns/common_validations.rb
module CommonValidations
  class Validations < NamedValidations
    define :short_text, length(maximum: 80)...
    define :long_text, length(maximum: 1000)...
    define :email do |*opts|
      short_text.format({ with: /@/, allow_blank: true }, *opts)
    end
  end

  class_methods do
    def vals
      Validations.new.presence(true)
    end
    # この例では起点だけメソッドにしているが、
    # short_text、long_textなどすべてメソッドにしてもよい。
    # Validations.aliases - NamedValidations.aliases で定義リストを得られる。
  end
end
post.rb
class Post < ApplicationRecord
  include CommonValidations
  validates :title, vals.short_text
  validates :author_name, vals.short_text
  validates :author_mail, vals.email
end
3
3
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
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?