🚀

【Ruby/Rails】感嘆符(!)付きメソッドの意味と違いまとめ|破壊的メソッドと例外発生の使い分け

に公開

はじめに

Railsを学び始めた頃、メソッド名の後ろに付いている感嘆符(ビックリマーク)!を見て「これは一体何だ!?」と戸惑ったのをよく覚えています。
そして、調べてみると「思っていた答えと違うな」と感じたことがあったなと記憶しています。
初学者にとってRailsの感嘆符!が付いているメソッドがややこしい原因は、後述するように

  • 破壊的メソッド
  • 例外を出すメソッド

の2種類が主にあり、見た目だけでは区別ができないからではないか?と考えました。
これらの区別がつかないまま、検索をした結果、本来得たい回答にたどり着けないのではないかと。。。

そこで、本記事では初学者にわかりやすいようにこれらを解説したいと思います。

対象読者

Railsを学び始めた方

Railsで「!」がややこしい理由

感嘆符が付いているメソッドは、主に以下の2つがあります。

  • 破壊的メソッド
  • 例外を出すメソッド

ところがこれらは、初学者にとっては区別がつきません。

具体的には、
破壊的メソッド

array.sort!

例外を出すメソッド

article.save!

どちらもメソッド名の最後に!が付いているので、同じに見えてしまいますね。
しかし、それぞれの!には異なる意味があります。
それでは、それぞれの意味や挙動について見ていくことにしましょう。

「!」が持つ2つの意味

破壊的メソッド

主にRubyのメソッドが該当します。
元のオブジェクトを変更するメソッドで、簡単に言うと自分自身を更新するメソッドになります。

どういうことか?
具体例を見てみましょう。

以下のように配列を作り、順番に並び替えて出力したい場合を考えます。

array = [1,3,2]
result = array.sort
p array # => [1,3,2]
p result # => [1,2,3]

並び替えが出来ました!

しかし、並び替えの途中でresultという新たな配列を作り出してしまっています。
できれば元の配列をそのまま並び替えたいところです。
ということで、以下のようにしてみました。

array = [1,3,2]
array = array.sort
p array  # => [1,2,3] 

このようにarray上書きすることで、1つの配列で並び替えができましたね!
しかし、array = array.sortのように、何回もarrayと書くのは面倒ですね、、、

そんな時に使えるのが破壊的メソッドです!

array = [1,3,2]
array.sort!
p array  # => [1,2,3] (元の配列が変更されている)

このように、元のオブジェクト(今回はarray)を変更するメソッドを破壊的メソッドと呼びます。

例外を出すメソッド

主にRailsのActive Recordのメソッドが該当します。
主に使われるのは、DBのテーブルに対する処理が失敗したときに例外を発生させたい場合に使用されます。

、、、と言われても困りますよね?
具体的に見ていきましょう!

例として、掲示板を作成するcreateアクションを考えてみましょう。

class BoardsController < ApplicationController
  def create
    @board = Boards.new(board_params)
    if @board.save
      # Boardsテーブルにレコードの保存が成功した場合の処理
    else
      # Boardsテーブルにレコードの保存が失敗した場合の処理
    end
  end
end

ここで@board.saveは、成功すればtrue、失敗したらfalseを返します。
そう、saveメソッドでは、保存に失敗しても例外(エラー)が発生しないのです。

「このコードみたいに保存に失敗したら、if文で失敗したときの処理を書けば充分じゃん?」と思われるかもしれませんが、そうもいかず、例外を発生させたい場合があります。
例えば、トランザクションで保存に失敗したらロールバックしたい場合などが該当しますが、今回は初学者用の説明ということでこの説明は割愛します。

ともかく、save失敗したら例外を発生させたい状況が出てきます。
そんな時に使用するのが!付きのメソッドです。

class BoardsController < ApplicationController
  def create
    @board = Boards.new(board_params)
    @board.save!
  end
end

このコードはちょっと実用的では無いかもしれませんが、@board.save!で保存が失敗するとエラーが発生し、エラー画面が出てきます。

このように、テーブルへの操作に対して失敗したら例外を発生させたい場合に使用される!付きのメソッドもあります。

見分け方

Railsの学習中に!が付いているメソッドが出てきた場合、「このメソッドは、破壊的メソッドなのか?はたまた例外を出すメソッドなのか?」判別に困りますよね。

完全に正確とは言えませんが、初学者のうちはデータベース操作かどうかで見分けると、おおよその判断がしやすくなります。

具体例

破壊的メソッド

  • upcase! 文字列を大文字に変換
  • chomp! 文字列の末尾の改行を削除
  • gsub! 正規表現による文字列置換
  • uniq! 配列から重複した要素を削除
  • strip! 前後のホワイトスペース(改行コード、半角スペース、タブ)を除去

など、文字列や配列に変更を加えるメソッドをRailsやRubyを勉強し始めると見かけるかと思います。
これらは、元のオブジェクトを変更する破壊的メソッドです。

例外を出すメソッド

  • create! レコードの作成
  • update! レコードの更新
  • destroy! レコードの削除
  • find_by! レコードの検索

など、Railsでテーブルの操作を行うメソッドで!が付いているメソッドを見かけると思います。
これらは、失敗した場合に例外を発生させるメソッドになります。

最後に

いかがでしたでしょうか?
私自身もRailsを勉強したての頃に、find_by!を見て「!が付いてるからこれは自身を更新するのか?」と混乱した記憶があります。

この記事が、初学者の方々の理解の一助になれれば幸いです。

参考

Discussion