😇

Railsのデバッグに役立ちそうなコマンドやメソッド

2023/03/02に公開

おはようございます。
スペースマーケットでWebエンジニアをしているs0arです。

花粉にやられています。
くしゃみでかなりカロリーを消費しているのでダイエットと呼んで差し支えないと思います。
実際鼻水とか涙で水抜きになってるのでこれ完全に減量です。

本題です。
Rails歴がそれなりになってきたので、Railsのデバッグをするときに知っていると少し役に立つかもしれないことをいくつか紹介しようと思います。

コマンド

Railsのコマンド一覧はここにあります。
以下、自分がデバッグによく使うかな…というものを抜粋します。

rails console rails c

読んで字の如く、Railsのコンソールを開きます。
Railsアプリケーションで実装されているメソッドを実行したりできます。
主にデータ周りの確認に使うことが多いですね。

Rails console内でヘルパーメソッドを使いたい

使いたいヘルパーをincludeすれば使えるようになります。
やらないと undefined methodと言われます。
意外と忘れやすいので一応(自分だけかも)

Rails consoleにコードの変更を反映したい

reload!しましょう。
(何回やっても「あっ…」ってなります)

rails routes

設定されているroutesが一覧表示できます。
URLとアクションの関係を洗い出すときに使えます。

rails db

あんまり使わないかもしれませんが、知っていると少し便利かもしれません。
rails db:migrateとかはよく使う気がしますが、実はrails dbでRailsアプリケーションが使用するDBのコマンドラインツールが起動します。
DBを確認するツール(Sequel Aceとか)を別途使っていればそちらから確認するのが良いかもしれませんが、コンソール上で手っ取り早く確認ができるので自分はちょいちょい使います。
でもActiveRecordに自信ニキネキのみなさんならRails Console上でコード書いたほうが早いかもしれません。お好みですね。

ちなみに、find_by_sqlとかselect_allとかを使えばRails Consoleからでも生SQLを実行できます。これもお好みで。

デバッグに使うコード

pp

オブジェクトを人間が読みやすい形で文字列にして出力してくれます。
inspectputsをあわせたやつです)
例えば以下のような感じになります。

class Hoge
    def initialize
        @name = 'hoge'
	@age = 20
    end
end

hoge = Hoge.new
pp hoge
#<Hoge:0x0000562f5f2048f8 @age=20, @name="hoge">

Railsだと諸々のインスタンスや、Controllerでパラメータの中身を確認するときに便利です。

ブレークポイントを設定する

確認したいところで止めたいこと、よくあると思います。

デバッグツール

binding.pry, byebug, ruby/debug等のツールを使用する方法です。
以下のようなコードを書くことで、その行で止まります。

  • binding.pry(pry-rails)
    • Railsで使用する対話型シェルをirbからpryに変えるgemです
      class Hoge
        def initialize
          @name = 'hoge'
          @age = 20
        end
      
        def update(name, age)
          @name = name
          binding.pry # ここでとまる
          @age = age
        end
      end
      
  • byebug
    • Railsに同梱されているデバッグ用のgemです
      class Hoge
        def initialize
          @name = 'hoge'
          @age = 20
        end
      
        def update(name, age)
          @name = name
          byebug # ここでとまる
          @age = age
        end
      end
      
  • ruby/debug
    • Rails7からはこちらが標準になるようです
      class Hoge
        def initialize
          @name = 'hoge'
          @age = 20
        end
      
        def update(name, age)
          @name = name
          binding.break # ここでとまる
          @age = age
        end
      end
      

raise

gemに依存せずに処理を止める方法としては、例外発生させる方法があります。
(ガチで止まるのでデバッグツールと比較すると利便性は低くなります)
怪しいところとか確認したいところでとりあえず例外を発生させるのは割とやると思います。
確認のためにraiseするだけなら、例外の型は指定せずにメッセージだけ指定する方法を使います。
メッセージのみを指定するとRuntimeErrorが発生します。

raise 'error'
# Main.rb:1:in `<main>': error (RuntimeError)

例外の型を指定してやると、その型の例外が発生します。
こちらはデバッグ時より実際の処理で書くことが多いコードですね。

raise ArgumentError, 'args error'
# Main.rb:1:in `<main>': args error (ArgumentError)

methods

対象のオブジェクトが実装しているメソッド一覧を返します。
「そもそも何が実装されてるんだっけ…?」とか「こういうメソッドって実装されてたっけ…?」とかを調べるときに使えます。
メソッド名のシンボルの配列を返すので、selectメソッドなどをチェーンして検索できます。

to_sql

ActiveRecordが発行するSQL文を返すメソッドです。

[1] pry(main)> User.order(updated_at: :desc).limit(10).to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`deleted_at` IS NULL ORDER BY `users`.`updated_at` DESC LIMIT 10"

「コードを書いたはいいけど、本当にこれでいいんだろうか…?」と不安になったらこれで実際のSQL文を確認したり、EXPLAINして実行計画を確認してみたりすると安心ですね。

余談ですが、やろうと思えばActiveRecord::Base.connection.executeメソッド使ってRails上で実行計画の出力までできそうですね(やらんでいい)。

まとめ

いざ挙げてみるとそんなになかった & 真新しいものはなかったですね。
逆に言うとこれぐらい知っていればデバッグはできますね(たぶん)
なにか思い出したらまた追記しようと思います。

おわりに

弊社では一緒にサービスを盛り上げていく仲間を募集中です。
少しでも「気になる!」と思ったあなた、カジュアルにお話しませんか?

https://www.wantedly.com/projects/1113570
https://www.wantedly.com/projects/1113544
https://www.wantedly.com/projects/1061116

GitHubで編集を提案
スペースマーケット Engineer Blog

Discussion