LoginSignup
0
1

More than 3 years have passed since last update.

Railsにおける例外処理

Last updated at Posted at 2020-04-06

rails db:seed

rails db:seedコマンドは、db/seeds.rbの記述に基づいて、データベースにレコードを作成するコマンドです。
クローン直後に投入したい初期データがある場合に利用します。
ターミナル

# 初期データの投入
$ rails db:seed

【例】チケット販売を例とします

db/seeds.rb
users = []
10000.times do |i|
 # usersに10000件新規ユーザーの情報を格納する
  users << User.new(name: "dummy-#{i+1}", ticket_count: 0)
end
# importメソッドの引数に配列を渡して、まとめてレコードを作成する
User.import users
User.find(500).update(ticket_count: 123456789)

今回は初期データの作成に、activerecord-importというgemを利用しています。
これは、通常通り10000回User.createするよりも、高速に大量のレコードを作成できるからです。
参考リンク
https://qiita.com/xend/items/79184ded56158ea1b97a

例外

例外とは、ある処理を実行した際の結果が、期待されるものと異なる状況を指します。 RubyおよびRuby on Railsでは、Exceptionというクラスを継承する形で様々な例外が定義されています。NoMethodError、SyntaxError などは、全てExceptionクラスの子孫クラスであり、例外です。例外が発生すると、それ以降の処理は中止され、実行されなくなってしまいます。
今回rails db:seedを実行して投入した初期データには、意図的に例外を発生させる値が投入されているものがあります。

db/seeds.rb
# ticket_countをint型で許容できる最大の値にする
User.find(500).update(ticket_count: 123456789)

idが500のユーザーのticket_countを、123456789に変更しています。これは、SQLのinteger型が許容できる最大の値であり、もし123456789より大きな値を保存しようとすると、RangeErrorという例外が発生し、保存に失敗します。ターミナルからrake distribute_ticket:executeを実行してみると、例外の発生するidが500までのユーザーについては、ticeket_countが10増加し、idが500番目以降のユーザーについては、例外が発生してしまったために、処理が中止され、ticket_countが増えていません。

例外処理

例外処理とは、例外が発生した場合に実行する処理のことを指します。Ruby on Railsの開発を行う際に、よく利用するのがrescueです。
上記のrubyプログラムを実行すると、「1 / 0」の処理を行った際に、ZeroDivisionErrorという例外が発生します。これは、数字を0で割ろうとすると発生する例外です。
beginブロックの内部で例外が発生したため、rescue以下の処理が実行されます。

rescue

rescueとは、発生した例外を捕捉し、例外が起こった際に呼び出される条件節です。
例外が発生しそうな部分をbeginから始まるブロックで囲み、ブロックの内部にrescueを記述して使用します。
サンプル

begin
# 数字を0で割ろうとすると、ZeroDivisionError例外が発生する
  1 / 0
rescue
# 例外が発生した時にrescue以下の処理が呼ばれる
  puts '0で割ることはできません'
end

通常、each, times, whileなどの繰り返しの最中に例外が発生した場合、繰り返し処理は途中で中止され、次のループが実行されることはありません。ただし、繰り返し処理の内部にrescueを記述していた場合、例外が発生したとしても、次のループに移ることができます。
大量のレコードを扱う処理で、例外が発生しても繰り返しを続行したい場合には、rescueを使いましょう。

トランザクション

複数のレコードの更新を1つにまとめて行うことを指します。トランザクションを用いることで、「全て実行されるか、それとも全て実行されないか」という1か0の状況を作ることができます。
サンプル

# ECサイトの購入処理を模した架空のコード
ActiveRecord::Base.transaction do 
  current_user.pay!(@product.price)
  current_user.confirm_purchase!(@product)
end

上記のサンプルは、購入処理を模した架空のコードです。pay!メソッドで商品の料金を払い、confirm_purchase!メソッドで商品の注文を確定させています。料金の支払いと、商品の購入の確定は、常に1つのまとまりとして考えます。トランザクションを用いることによって、「料金の支払いに失敗したけど、商品は購入できた」「料金は支払ったけど、注文の確定に失敗し商品が届かなかった」といった事態を防ぐことができます。

参考リンク

例外と呼んでいたものは、全てこのExceptionクラスを継承しています。
Ruby Exceptionクラス ドキュメント
ActiveRecord Transactions ドキュメント(英語)

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