0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今更だがvalid?, invalid?のプロセスを誤解していた件

Last updated at Posted at 2024-12-07

概要

業務でActiveModel::Validationsmix-inしたカスタムモデルでのレコード作成処理を実装しました。

その際にvalid?, invalid? メソッドの挙動を履き違えていたことに気がついたため、自戒の念を込めて本記事の執筆に至りました。

該当処理

以下ユーザーの作成処理を担うカスタムモデル(サンプル)です。

class CreateUser
  include ActiveModel::Validations

  attr_reader :name, :password

  def initialize(name, password)
    @name = name
    @password = password
  end

  def call
    # 任意の処理
    # ...

    # 問題があった場合にerrorsに追加
    errors.add(:base, '~が不正です')

    return if invalid?

    User.create!(
      name:,
      password:
    )
  end
end

当時の認識

当時の私は以下のような流れになると思っていました。

  1. valid?, invalid? メソッドの実行
  2. validationメソッドが実行
  3. errors オブジェクトに値が格納されているか検証され、その結果が返る

実際の挙動

実際の挙動は以下になりました。

  1. valid?, invalid? メソッドの実行
  2. errors オブジェクトがクリアされる
  3. validationメソッドが実行
  4. errors オブジェクトに値が格納されているか検証され、その結果が返る

そのため、以下のerrors.addで格納された情報は、後続のinvalid?の実行によってclearされます。
結果、無効なデータはないと判断され、ユーザー作成処理が実行されます。

# 問題があった場合にerrorsに追加
errors.add(:base, '~が不正です')

return if invalid?

Source

ActiveModel::Validationsのソースコードを確認しました。
errors.clearされることがわかりますね.

def valid?(context = nil)
  current_context = validation_context
  context_for_validation.context = context
  errors.clear
  run_validations!
ensure
  context_for_validation.context = current_context
end

def invalid?(context = nil)
  !valid?(context)
end

ref.

まとめ

以上です。
本記事の内容について、認識齟齬などあればコメントいただきたいです🙏

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?