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.

[Rails]レコードの保存系処理を書くときは validates を先に確認しよう

Last updated at Posted at 2018-10-25

久々の失敗談エントリです。素人かよって言われるレベルですがよろしければこのままお進みください。

前提

Model

こんな Model クラスがあったとします。

app/models/some.rb
class Some < ApplicationRecord
  validates :kind, length: { maximum: 4 }, unless: :skip_foo_validation
  attr_accessor :skip_foo_validation
end

Controller

で、コントローラでこんなかんじに Some のレコードを作成します。

app/controllers/hoge/foo_controller.rb
record = Some.find_or_create_by(kind: 'some_kind')

今回の状況

別の用途があってここで作成したレコードの主キー(Some では自動採番による id が主キーであるとします。)をすぐ確認したいとします。

app/controllers/hoge/foo_controller.rb
puts record.id # => nil

nil...だと...?

Some.find_by(kind: 'some_kind') #=> nil

DBにもまだ保存されていません。あれ、record.save とか呼ばなきゃ保存までされないんでしたっけ?そんなはずはないんだが。。。( ゚д゚)

ここでクエスチョン

Q. record.id が nil になる理由と対応方法を回答してください。

ということでさあ困りました。これはどういうことなんでしょうか。

回答例

まあ大したオチはないんですが、バリデーションがまだ通っていないためレコードのINSERTが行われていないことが理由です。 find_byでレコードがなかった時点でINSERTされてないのはわかりましたが理由が謎でした。

何故判明したかといいますと、errors に思いっきりバリデーションのエラー内容が出ていたためです。 我ながらひどい。(細かいところは省略してます)

puts record.errors.inspect
# => #<ActiveModel::Errors:**********
#  @base=#<Some id: nil, kind: 'some_kind', *****>,
#  @details={:kind=>[{:error=>:too_long, :count=>4}]},
#  @details={:kind=>["4文字以内で入力してください。"]}
# >

ということで入力内容の問題ということがわかりました。
バリデーションが通るような値を kind に渡せばいいんですが、今回は find_or_create_by にブロックを渡してスキップ用の値をセットする方向で対処してみます。

app/controllers/hoge/foo_controller.rb
record = Some.find_or_create_by(kind: :some_kind) do |rec|
  rec.skip_foo_validation = true
end

こんどは大丈夫ですね。

app/controllers/hoge/foo_controller.rb
puts record.id # => 1

教訓

例えばチームで開発していて、該当の Model クラスを自分以外の人が作っている場合は自分の知らない validates が含まれているケースは多々あると思います。保存処理を行いたい Modelクラスの validates はひととおり目を通しておくといいとおもいます。(ブーメラン)
今回は find_or_create_by 使用していましたが、特にこのメソッドに限った話ではないですしね。

※ちなみにぶっちゃけ30分以上ハマりました/(^o^)\

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