0
0

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.

validate条件に関連オブジェクトの値を使う時の注意点

0
Last updated at Posted at 2013-12-12

今回学んだこと

validate が実行されるタイミングは、オブジェクトの関連付けが行われる前である

(後だと思ってました)

前提条件

下記のようなリレーションを定義済み

blog.rb
class Blog < ActiveRecord::Base
  has_many :entries
end

Entryには writer_id という属性が定義されているものとする

entry.rb
class Entry < ActiveRecord::Base
  belongs_to: blog
  # writer_id という列をもっている
end

やりたいこと

一つのBlogがもつEntry内で、writer_idが重複しないようなvalidateを定義したい

最初に試した方法(失敗例)

writer_id の重複を検知しようとしました。
しかし、validate処理が実行される時点では、
EntryとBlogが関連付けられていないため
(要するに、重複していないため)
検知できませんでした。

entry.rb
class Entry < ActiveRecord::Base
  belongs_to: blog
  validate :unique_writer_id
  
  private
  def unique_writer_id
    # 兄弟のwriter_idをすべて取得する
    writer_id_arr = blog.entries.pluck(:writer_id)

    # 重複するものがあったらエラーとする...つもりが、エラーとならなかった
    if writer_id_arr.size == writer_id_arr.uniq.size
      errors.add(:writer_id)
    end
  end
end

正解

重複の検知ではなく、
writer_idの存在チェックにすることで解決しました。

entry.rb
class Entry < ActiveRecord::Base
  belongs_to: blog
  validate :unique_writer_id
  
  private
  def unique_writer_id
    # 兄弟のwriter_idをすべて取得する
    writer_id_arr = blog.entries.pluck(:writer_id)

    # 自分自身のwriter_idが既に存在したらエラーとする
    if writer_id_arr.include? writer_id
      errors.add(:writer_id)
    end
  end
end

学習に費やしたお時間

3時間 orz

0
0
3

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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?