今回学んだこと
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