LoginSignup
0
0

More than 3 years have passed since last update.

【Rails】コールバックでターミナルにバリデーションエラーを出力する

Last updated at Posted at 2020-08-01

◯◯.saveや◯◯.createに失敗する時の原因を教えてくれなくて困る

例えばmessageモデルのインスタンスのsaveに失敗した時

Started POST "/groups/2/messages" for ::1 at 2020-08-01 13:56:59 +0900
Processing by MessagesController#create as */*
  Parameters: {"authenticity_token"=>"PKsrO+YPeqs8AmQ+sB+9YacFtKCb+gpdTkHPTgxG4/vs6wE0swZrWNYXKyBe4ipm9aQDII8PpHSUzL3JPeYPpw==", "message"=>{"content"=>""}, "group_id"=>"2"}
  User Load (25.1ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 6 ORDER BY `users`.`id` ASC LIMIT 1
  Group Load (0.6ms)  SELECT `groups`.* FROM `groups` WHERE `groups`.`id` = 2 LIMIT 1
  ↳ app/controllers/messages_controller.rb:30:in `set_group'
   (0.2ms)  BEGIN
  ↳ app/controllers/messages_controller.rb:11:in `create'
  User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
  ↳ app/controllers/messages_controller.rb:11:in `create'
   (0.2ms)  ROLLBACK

ROLLBACKとだけ出てパッと見では原因がわからない。

【対策1】コントローラでsave!を使う方法

savecreatesave!create!にするとどのバリデーションが原因なのかエラーが表示される。

スクリーンショット 2020-08-01 13.58.42.png

【対策2】モデルでコールバックを使う方法

本題。after_validationを使ってself.errors.messagesなどをputsメソッドで表示する。

<メリット>
・deviseを使ったuserモデルのように、コントローラを触るのが面倒な場合でも使える
・application_record.rbに一度書けばそれぞれのモデルで使える

手順1. pry-railsのgemを導入する

バリデーションエラーが発生した場合にbinding.pryを走らせたいので、いつもどおりpry-railsのgemを導入する。

Gemfile
group :development, :test do
  〜省略〜
  gem 'pry-rails'
end
ターミナル
bundle

手順2. models/application_record.rbにコールバックを追加する

models/application_record.rbに以下を追加する。

application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  ## 以下を追加する

  after_validation :display_validation_result

  private
  def display_validation_result
   ## development以外のときはオフ
    return false unless Rails.env.development?

    puts "============【display_validation_result】============"
    puts "◆◆◆◆◆◆#{self.class.name}モデル◆◆◆◆◆◆"
    puts "+++++属性値一覧++++++"
    self.attributes.each do |key, value|
      puts "#{key}: #{value}"
    end

    ## deviseを使ったuserモデルの場合passwordもputsする
    if self.class.name == "User"
      puts "password: #{self.password}"
    end

    puts "++++++++++++++++++++++++++++"
    ## メインはここから
    puts "★★★★★★バリデーションエラー★★★★★★"
    if self.errors.messages.length == 0
      puts "発生しませんでした"
    else
      puts "バリデーションエラー発生"
      puts self.errors.messages
      binding.pry
    end
    puts "★★★★★★★★★★★★★★★★★★★★★★★★★★★★★"
    puts "==========================="
  end

end

やっていることはバリデーションエラーが発生した時(self.errors.messages.lengthが0出ない時)にself.errors.messagesをターミナルに表示してbinding.pryを走らせているだけ。その他はおまけの情報。

結果

バリデーションエラーが発生してインスタンスのsaveに失敗する時、以下のようにターミナルに出力される。

============【display_validation_result】============
◆◆◆◆◆◆Userモデル◆◆◆◆◆◆
+++++属性一覧++++++
"id: "
"email: dwada"
"encrypted_password: $2a$11$zvwhx8qOe7u62tLbGQCaMOjItYjtjzg5yuaInysQ9wd15SMpMsBti"
"nickname: dadwa"
"first_name: dwadad"
"first_name_reading: dadawdwa"
"last_name: dwada"
"last_name_reading: dadwadwa"
"birthday: 2015-04-10"
"reset_password_token: "
"reset_password_sent_at: "
"remember_created_at: "
"password: dwadad"
++++++++++++++++++++++++++++
★★★★★★バリデーションエラー★★★★★★
バリデーションエラー発生
{:email=>["は不正な値です"], :password_confirmation=>["とパスワードの入力が一致しません"], :first_name_reading=>["はカタカナで入力して下さい。"], :last_name_reading=>["はカタカナで入力して下さい。"], :password=>["は不正な値です"]}

From: /Users/hogehoge/hogehoge/app/models/application_record.rb:27 ApplicationRecord#display_validation_result:

     6: def display_validation_result
     7:   puts "============【display_validation_result】============"
     8:   puts "◆◆◆◆◆◆#{self.class.name}モデル◆◆◆◆◆◆"
     9:   puts "+++++属性一覧++++++"
    10:   self.attributes.each do |key, value|
    11:     p "#{key}: #{value}"
    12:   end
    13: 
    14:   if self.class.name == "User"
    15:     p "password: #{self.password}"
    16:   end
    17: 
    18:   puts "++++++++++++++++++++++++++++"
    19:   puts "★★★★★★バリデーションエラー★★★★★★"
    20:   if self.errors.messages.length == 0
    21:     puts "発生しませんでした"
    22:   else
    23:     puts "バリデーションエラー発生"
    24:     puts self.errors.messages
    25:     binding.pry
    26:   end
 => 27:   puts "★★★★★★★★★★★★★★★★★★★★★★★★★★★★★"
    28:   puts "==========================="
    29: end

[1] pry(#<User>)> 
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