By

(Rails) Modelクラスでの条件分岐

ビジネスバンクグループ エンジニア の高橋 慶太です。

今回は、RailsのModelクラス内で実施するバリデーションについて、ある条件の時だけバリデーションを行いたい場合の方法について書きたいと思います。

if、unless文

if、unless文を用いて、ある条件の場合のみバリデーションを実行する場合、以下のように記述します。

  class Sample < ActiveRecord::Base
    # name項目に値が入力されている場合のみ、8〜32桁の範囲内かどうかの入力チェックを行う。

    # if文で書く場合
    # 最小文字数
    validates :name, length: { minimum: 8 }, if: "name.present?"
    # 最大文字数
    validates :name, length: { maximum: 32 }, if: "name.present?"

    # unless文で書く場合
    # 最小文字数
    validates :name, length: { minimum: 8 }, unless: "name.blank?"
    # 最大文字数
    validates :name, length: { maximum: 32 }, unless: "name.blank?"

    # 下記のように、まとめて書くこともできます
    with_options if: ":name.present?" do |model|
      model.validates :name, length: { minimum: 8 }
      model.validates :name, length: { maximum: 32 }
    end
  end

:on

1つのModelに対して複数の箇所で登録処理などを行っている場合に、 箇所によってバリデーションを行う/行わないを制御したい場合があります。
このような場合、:onを用いることで制御することができます。

  class SampleModel < ActiveRecord::Base
    # 最大文字数
    validates :name, length: { maximum: 32 }, on: :execute_validation
    # 最小文字数
    validates :name, length: { minimum: 1 }, on: :execute_validation
  end

  class SampleService
    def create_with_validation
      model = SampleModel.new
      model.name = "test"
      # saveメソッドの引数に「:execute_validation」を指定しているため、
      # modelクラスの「on: :execute_validation」指定されているバリデーションが実行されます
      model.save!(:execute_validation)
    end
  end

(補足)RSpecを使ったテストの記述

:onの記述についてRSpecを使ってテストする場合、以下のように記述することでテストすることができます。

  describe SampleModel do
    describe "#validate" do
      # nameに33桁を指定
      let(:model) { build :sample_model, name: "123456789012345678901234567890123" }

      it "when name is longer than 32" do
        # errors_onメソッドの引数にcontextの指定をすることで:onのテストが可能
        expect(model).to have(1).errors_on(:name, context: :execute_validation)
      end
    end
  end

エンジニア募集中!

ビジネスバンクグループではエンジニアを募集中しています。

弊社が採用しているテクノロジや開発環境に興味を持った方は、 ここから是非エントリー を!