今回は、Rails開発で活躍するデバッグ手法5選を紹介したいと思います。Railsでは様々なデバッグ手法やgemが用意されていますが、今回はその中でも頻繁に使われるもののみをまとめました。
個人的には、これら5つのデバッグ手法が使えればRailsでのアプリケーション開発は十分だと思います。ぜひこの機会にマスターしていきましょう。
デバッグ手法5選
使うべきデバッグ手法は以下の5つです。この後の項目で、導入手順や使い方についてそれぞれ詳しく見ていきます。
- pp(printデバッグ)
- rails console
- pry-rail
- (binding.pry)
- pry-byebug
ppメソッド
pp(printデバッグ)とはppメソッドをコード内に埋め込み、変数の値や実行された条件分岐を確認するデバッグ手法です。
ppメソッドとは「pretty print」の略で、オブジェクトを読みやすく表示してくれるメソッドです。原始的なデバッグ方法ですが、簡単なコードであれば最も効率よくデバッグできる手法でもあります。
ではその使い方を見ていきましょう。例えば、以下のようにArticle(投稿記事)を一覧表示するアクションが定義されていたとします。
def index
@articles = Article.all
end
では、どのような投稿記事が取得されているか@articlesの中身を確認してみましょう。ppメソッドを@articlesの直下に記述します。
def index
@articles = Article.all
pp @articles
end
サーバーを立ち上げ、ターミナルのログを確認してみます。すると以下のように、@articlesの中身が表示されていることが分かると思います。
[#<Article:0x00007fd1d61cb358
id: 1,
url: "aaa",
post: "テスト1",
created_at: Sun, 27 Sep 2020 23:51:20 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:20 UTC +00:00>,
#<Article:0x00007fd1d538f280
id: 2,
url: "bbb",
post: "テスト2",
created_at: Sun, 27 Sep 2020 23:51:32 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:32 UTC +00:00>,
#<Article:0x00007fd1d538f1b8
id: 3,
url: "ccc",
post: "テスト3",
created_at: Sun, 27 Sep 2020 23:51:45 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:45 UTC +00:00>]
このようにppメソッドを使用することで、インスタンス変数の中身やどこまでコードが来ているかなどを確認することができます。
rails console
rails consoleとは、ターミナル上でRubyのプログラムを実行したり、データベースを直接操作できたり、コードの動作確認などができるデバッグ手法です。
先ほどの@articlesの中身をrails consoleを使って見てみましょう。
ターミナルでrails consoleと入力します。
% rails console
irb>
irbが起動し、以下のように入力することで@articlesの中身を確認することができます。
% rails console
irb> @articles = Article.all
(0.8ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
Article Load (0.5ms) SELECT `articles`.* FROM `articles` LIMIT 11
=> #<ActiveRecord::Relation [#<Article id: 1, url: "aaa", post: "テスト1", created_at: "2020-09-27 23:51:20", updated_at: "2020-09-27 23:51:20">, #<Article id: 2, url: "bbb", post: "テスト2", created_at: "2020-09-27 23:51:32", updated_at: "2020-09-27 23:51:32">, #<Article id: 3, url: "ccc", post: "テスト3", created_at: "2020-09-27 23:51:45", updated_at: "2020-09-27 23:51:45">]>
rails consoleでは、URLを確認することも可能です。
% rails console
irb> app.articles_path
=> "/articles"
コントローラーとアクションからURLを確認することもできます。
% rails console
rirb> app.url_for(controller: 'articles', action: 'new')
=> "http://www.example.com/articles/new"
この他にもirbではクラス名を調べたり、継承元を確認できたりと様々な機能があります。詳しくはこちらの公式ドキュメントを参照してください。
library irb:https://docs.ruby-lang.org/ja/latest/library/irb.html
pry-rails
突然ですが、Rubyのコンソールには2種類存在しています。
1つがirb、もう1つがpryです。先ほどのrails consoleの項目を見ていただくと分かる通り、コンソールを起動するとデフォルトではirbが立ち上がるようになっています。
しかし、Railsで開発をするのであればirbではなく、迷わずpryを使いましょう。
Railsでpryを使用するには「pry-rails」というGemをインストールする必要があり、以下の手順で「pry-rails」を導入することができます。
①Gemfileに「pry-rails」を記載
gem 'pry-rails'
②bundle installを実行
③rails consoleを実行し、irbではなくpryになっているか確認
では、なぜirbよりもpryが推奨されているのでしょうか?
pryを推奨する理由は以下の3つです。
- シンタックスハイライトが標準装備されている
- 便利なコマンドが標準装備されている
- shellコマンドが使用可能である
シンタックスハイライトが標準装備されている
まず何と言っても、シンタックスハイライト(出力結果が色付けされること)があることでコマンドの可読性が上がります。
試しにrails consoleを立ち上げ、以下の計算式を入力してみてください。
% rails console
Running via Spring preloader in process 36475
Loading development environment (Rails 6.0.3.3)
pry(main)> 6 * 6
=> 36
irbで色付けすることも可能ですが、それには新しく別のGemをインストールする必要があります。しかしpryを使用することで、簡単にシンタックスハイライトを装備することができるようになります。
便利なコマンドが標準装備されている
pryにはいくつかの組み込みコマンドが標準装備されており、それらを使用することで効率よくデバッグを行うことができます。
使用できるコマンドはrails consoleで「help」と打ち込むことで確認できます。実際に試してみてください。
% rails console
Running via Spring preloader in process 36475
Loading development environment (Rails 6.0.3.3)
pry(main)> help
Help
help Show a list of commands or information about a specific command.
Context
cd Move into a new context (object or scope).
find-method Recursively search for a method within a class/module or the current namespace.
ls Show the list of vars and methods in the current scope.
pry-backtrace Show the backtrace for the pry session.
raise-up Raise an exception out of the current pry instance.
reset Reset the repl to a clean state.
watch Watch the value of an expression and print a notification whenever it changes.
whereami Show code surrounding the current context.
wtf? Show the backtrace of the most recent exception.
Editing
! Clear the input buffer.
以下省略
例えばですが「show-routes」という組み込みコマンドがあります。これはアプリケーションで定義されているルーティングを確認することができるコマンドです。
% rails console
pry(main)> show-routes
Prefix Verb URI Pattern Controller#Action
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format)
以下省略
また「show-models」というコマンドもあります。これはアプリケーションにある全てのモデルとそのカラム、さらにはデータタイプを返してくれるコマンドになります。
% rails console
pry(main)> show-models
(5.6ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
ActionMailbox::InboundEmail
Table doesn't exist
has_one :raw_email_attachment (class_name :ActiveStorage::Attachment)
has_one :raw_email_blob (through :raw_email_attachment, class_name :ActiveStorage::Blob)
ActionText::RichText
Table doesn't exist
belongs_to :record
has_many :embeds_attachments (class_name :ActiveStorage::Attachment)
has_many :embeds_blobs (through :embeds_attachments, class_name :ActiveStorage::Blob)
ActiveStorage::Attachment
Table doesn't exist
belongs_to :blob (class_name :ActiveStorage::Blob)
belongs_to :record
ActiveStorage::Blob
Table doesn't exist
has_many :attachments
has_one :preview_image_attachment (class_name :ActiveStorage::Attachment)
has_one :preview_image_blob (through :preview_image_attachment, class_name :ActiveStorage::Blob)
ApplicationRecord
Table doesn't exist
Article
id: integer
url: string
post: string
created_at: datetime
updated_at: datetime
「reload!」というコマンドもあり、これを実行することでアプリケーションが再読み込みされます。
% rails console
pry(main)> reload!
Reloading...
=> true
shellコマンドが使用可能
pryはshellと結合することによって、shellコマンドをコンソール上で入力することができるようになります。
% rails console
pry(main)> .ls
Gemfile babel.config.js lib public yarn.lock
Gemfile.lock bin log storage
README.md config node_modules test
Rakefile config.ru package.json tmp
app db postcss.config.js vendor
pry(main)> .pwd
/Users/ユーザー名/Desktop/debug-app
このようにpryを使用することで、より拡張性が高い機能を使うことができます。こういった理由から、Railsで開発する際は必ず「pry-rails」をインストールするようにしましょう。
(binding.pry)
binding.pryは先ほど解説したGem「pry-rails」をインストールすることで使用できる機能です。binding.pryを使用することで、ブレークポイントをコード内に挿入することができます。
binding.pryは先ほどの「pry-rails」の項目に含めても良かったのですが、デバッグで一番使える機能と言っても過言ではないので、新たに項目を追加して記載する形にしています。
では、binding.pryの使い方を見ていきましょう。例えば、以下のようにArticle(投稿記事)を一覧表示するアクションが定義されていたとします。
def index
@articles = Article.all
end
ここにbinding.pryを差し込み、@articlesの中身がどのようになっているか確認してみます。以下のように記述し、サーバーを立ち上げ、ブラウザにアクセスしてみましょう。
def index
@articles = Article.all
binding.pry
end
するとターミナル上では、以下のようにプログラムの処理が止まっていると思います。
6: def index
7: @articles = Article.all
=> 8: binding.pry
9: end
pry(#<ArticlesController>)>
ここで@articlesと入力しましょう。そうすることで、@articlesの中身を確認することができます。
6: def index
7: @articles = Article.all
=> 8: binding.pry
9: end
pry(#<ArticlesController>)> @articles
Article Load (13.3ms) SELECT `articles`.* FROM `articles`
↳ app/controllers/articles_controller.rb:8:in `index'
=> [#<Article:0x00007fd8a7ecf2e8
id: 1,
url: "aaa",
post: "テスト1",
created_at: Sun, 27 Sep 2020 23:51:20 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:20 UTC +00:00>,
#<Article:0x00007fd8a9880ac0
id: 2,
url: "bbb",
post: "テスト2",
created_at: Sun, 27 Sep 2020 23:51:32 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:32 UTC +00:00>,
#<Article:0x00007fd8a98807f0
id: 3,
url: "ccc",
post: "テスト3",
created_at: Sun, 27 Sep 2020 23:51:45 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:45 UTC +00:00>]
また、ビューファイル(HTML)でもbinding.pryを使用することができます。ビューで使用する場合は、以下のように<% %>で囲むことで記述が可能になり、articleの中身を確認することができます。
<tbody>
<% @articles.each do |article| %>
<% binding.pry %>
<tr>
以下省略
14: <tbody>
15: <% @articles.each do |article| %>
=> 16: <% binding.pry %>
17: <tr>
pry(#<#<Class:0x00007fd8c12d7f48>>)> article
=> #<Article:0x00007fd8bed70ea8
id: 1,
url: "aaa",
post: "テスト1",
created_at: Sun, 27 Sep 2020 23:51:20 UTC +00:00,
updated_at: Sun, 27 Sep 2020 23:51:20 UTC +00:00>
pry(#<#<Class:0x00007fd8c12d7f48>>)> exit!
このようにbinding.pryを使用することで簡単にブレークポイントを作り、値の中身を確認することができます。正直このbinding.pryがRailsのデバッグで最も重要であるといっても過言ではないので、ぜひ理解しておきましょう。
pry-byebug
「pry-rails」の他にも「pry-byebug」と呼ばれるデバッグ用のGemが用意されています。「pry-byebug」をインストールすることで、binding.pryを使用することができるだけでなく、様々な便利コマンドを使用することができます。
頻繁に使用する便利コマンドは以下の5つです。
- next
- step
- finish
- continue
- break
「pry-rails」は必要最低限のデバッグ機能があれば問題ない方、「pry-buybug」は様々なデバッグ手法を試したい方向けです。
「pry-buybug」は以下の手順でインストールすることができます。
①Gemfileに「pry-buybug」を記載
gem 'pry-buybug'
②bundle installを実行
では「pry-byebug」の便利コマンドを見ていきましょう。
その前に以下のように、ビューファイルの中にbinding.pryを仕込んでおきました。
<tbody>
<% @articles.each do |article| %>
<% binding.pry %>
<tr>
以下省略
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
=> 17: <tr>
pry(#<#<Class:0x00007fd8c12d7f48>>)>
next
nextを使用することで次の行に移ることができます。
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
=> 17: <tr>
pry(#<#<Class:0x00007fd8c12d7f48>>)> next
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
17: <tr>
=> 18: <td><%= article.url %></td>
以下省略
step
stepはメソッドの実行もしくは次の行に移動できるコマンドです。nextは単純に次の行に移動、stepはメソッドを実行し、なければ次の行に移動と覚えていただけたらと思います。
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
=> 17: <tr>
pry(#<#<Class:0x00007fd8c12d7f48>>)> step
168: def safe_concat(value)
=> 169: raise SafeConcatError unless html_safe?
170: original_concat(value)
171: end
finish
finishはメソッドの実行を終了し、次の行に移動できるコマンドです。step→finishという流れで覚えていただけたらと思います。
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
=> 17: <tr>
pry(#<#<Class:0x00007fd8c12d7f48>>)> step
168: def safe_concat(value)
=> 169: raise SafeConcatError unless html_safe?
170: original_concat(value)
171: end
pry(#<#<Class:0x00007fd8c12d7f48>>)> finish
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
17: <tr>
=> 18: <td><%= article.url %></td>
continue
continueを実行することで、プログラムの実行を続けつつ、pryモードを終了させることができます。exitでも構いません。
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
=> 17: <tr>
pry(#<#<Class:0x00007fd8c12d7f48>>)> continue
Rendered articles/index.html.erb within layouts/application (Duration: 292219.9ms | Allocations: 592597)
[Webpacker] Everything's up-to-date. Nothing to do
Completed 200 OK in 292283ms (Views: 292264.1ms | ActiveRecord: 7.9ms | Allocations: 600860)
break
breakはブレークポイントをすることができるコマンドです。「break 行数」を入力することで自在にブレークポイントを移動できます。
14: <tbody>
15: <% @articles.each do |article| %>
16: <% binding.pry %>
=> 17: <tr>
18: <td><%= article.url %></td>
19: <td><%= article.post %></td>
20: <td><%= link_to 'Show', article %></td>
21: <td><%= link_to 'Edit', edit_article_path(article) %></td>
22: <td><%= link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' } %></td>
pry(#<#<Class:0x00007f95e931c3c0>>)> break 20
18: <td><%= article.url %></td>
19: <td><%= article.post %></td>
=> 20: <td><%= link_to 'Show', article %></td>
21: <td><%= link_to 'Edit', edit_article_path(article) %></td>
22: <td><%= link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' } %></td>
このように「pry-byebug」を使用することで、「pry-rails」の1歩上のデバッグができるようになります。
pry-rails vs pry-byebug
ここまでで似たような2つのGem「pry-rails」と「pry-byebug」を紹介しました。では、どちらを使うのが良いのでしょうか?
どちらも使用してみて、個人的には「pry-byebug」一択かなと思います。
何より、自由にブレークポイントを移動できる点が非常に便利で、「pry-byebug」さえあれば1通りのデバッグは可能です。
Railsの開発ではぜひ「pry-byebug」を導入しておきましょう。
参考
library irb:
https://docs.ruby-lang.org/ja/latest/library/irb.html
pry Github:
https://github.com/pry/pry
pry-buybug Github:
https://github.com/deivid-rodriguez/pry-byebug
TIM Labs:
http://labs.timedia.co.jp/2011/12/rubyist-should-use-pry.html
今更聞けないpryの使い方と便利プラグイン集:
https://qiita.com/k0kubun/items/b118e9ccaef8707c4d9f#cd-ls-tab%E8%A3%9C%E5%AE%8C
今回は、Railsの開発で活躍するデバッグ手法5選を紹介しました。これらが使いこなせるだけでもアプリケーション開発がグッとしやすくなります。ぜひ理解した上で開発にあたっていただけたらと思います。