見出し画像

備忘録2:Rails-例外処理について

転職のための3月6日から某スクールにでプログラミング学習を始めた32歳のおっさんです。時系列でHTML⇨CSS⇨Ruby & JavaScriptを学習中。

学習内容:例外処理の手法を学ぶ

1:開幕の自問自答

①例外処理ってなんず?
 ⇨何か例外なことが起こった時にする処理です。
②その例外が何かって聞いてんすよ。
 ⇨開発者が意図・予想しない処理結果が起きた時に行うものです。
③テストしてるのに?
 ⇨何事も例外は起きるんですよ。
④結局、例外が起きると何がマズいんですか?
 ⇨例外が発生するとそこで処理が止まるので色々とマズいです。

と、言うわけで例外処理についてです。
何事も想定GUYのことは起きるので必須なやつです。

2:今回やること-詫び石の正常な配布を行う

スクリーンショット 2021-05-01 23.54.12

※SSは実装テストが終了した後の物

データベースにこんな感じのデータを用意し
全ユーザーに対して正常に詫び石を配布する。
今回はID500の石(tikect_count)がmysqlの仕様上の限界値に達しており
この状態で詫び石の配布を行うとID500でエラーが発生し処理が止まる。

それではマズいので、このような事態に陥った時
ID500は処理をスルーしてID500以外は正常に処理を終えるコードを書く。


3:事前準備-ユーザーデータを用意する

スクリーンショット 2021-05-02 0.07.45

Gem:Activerecord-impotをインストールする。
※モデルが配列を受け取った際にまとめてレコードを作成できるGem。
未使用:User.newを行う⇨テーブルにレコードを保存する ×10000
使用;10000回User.newを行う⇨テーブルに10000idをまとめて保存する。

User.import users
User.find(500).update(ticket_count 2147483647)

ID500のユーザーのみticket_countを仕様上の限界値に上書きしている。


4:詫び石タスクを作成する(失敗例)

rails g task タスク名
これでRakeファイルを作成する。

スクリーンショット 2021-05-02 0.15.58

次にこんな感じに記述する。
内容はdescにもある通り
全ユーザーの :ticket_count カラムを10増加させる。

初出のメソッド

namespace   do ~ end
複数のタスクをグループ分けして1つにまとめる。
多分ニュアンス的にはテストで使う describe みたいな感じ。多分。

desc
処理内容の説明を書く。分かりやすくするようにするメモ的な感じ。
テストで言う context 的な感じで合ってると思う。

task   do ~ end
ここに実際のタスクを記述する。

environment
タスクの処理をアプリケーション環境に依存させた上で実行させる。
今回のアプリケーションはRailsを指す。
今回のケースでは、Userモデルを扱うために必要となる。
「task タスク名: :environment」と記述する。

increment
カラムと数字を引数にし、引数の数だけカラムの値を増加させる。
incrementに限らないが「!」を付けると処理が失敗した際に
false ではなく 例外を発生させることができる。
例外が発生すると、処理は止まらずに実行される。
ただし、今回は例外に対する処理が指定されていないため。止まる。
rails namespace名:task名 で実行する。

今回だと
rails distribute_tikect:execute
となる。


スクリーンショット 2021-05-02 0.36.22

この状態で処理を実行すると、Id500で処理が止まり
Id501以降の数値が増加せず不祥事となり
追加の詫び石を要求されることになる。


5:詫び石タスクを作成する(成功例)

スクリーンショット 2021-05-02 0.42.59

※先程とは別のタスク用ファイルを作成している。
こんな感じで記述する。これで2度に渡る詫び石配布が終了する。

初出のメソッド

begin
例外が発生しそうな箇所を囲って処理を実行する。
何が起きても絶対に1回は実行される。
後述の rescue とセットで使うと良い感じ。

rescue
例外が発生した時に呼び出される。 begin と仲が良い。
「rescue => e」は発生した例外内容を 変数e に格納するもの。
「Rails.logger.debug e.message」で例外のログを表示している。


6:例外を自分で発生させる

スクリーンショット 2021-05-02 1.11.56

こんな感じで記述する。
なぜ例外を自分で発生させるのかと言うと
あらかじめ、例外が発生しそうな箇所を把握出来ていれば
場所の特定も修正も素早く行えるようになるため。

このコードは詫び石を配布した際に
「石の数が最大値に達する or 最大値を超える物が無いか?」
を調べている。
「最大値-10」よりも多い物が存在すれば例外が発生する。

初出のメソッド

raise
「raise 発生させたい例外クラス, 'エラーメッセージ'」
という記述の仕方をする。
今回は比較演算子のエラーで発生する RangeError を見たいため
第一引数に RangeError を設定している。
NoMethodError や SyntaxErrorなども例外クラスの仲間。


7:無かったことにする

スクリーンショット 2021-05-02 1.10.11

このように記述する。
この処理は「このタスクで行われた処理をひとまとめにする処理」である。
つまり「全て成功 or 全て失敗」 の2つに分けることができる。

今回の場合
「ID500で例外が発生し、ID500で処理が失敗する」ため
「今回行われたID1〜500の処理は全て失敗とみなされる」

なので、詫び石を配布する際は初めからトランザクションを行なっておけば
仮に例外の発生する箇所が有ったとしても不祥事は起きずに済む。

初出のメソッド

transaction
ActiveRecord::Base.transaction do 〜 end と記述する。
前述の通り、例外が発生した際に全ての処理を無かったことに出来る。
人生もトランザクションが効けばどれほど良かったことか。

日本語訳は「取引する」


8:終わり

以上で、今回の例外処理については終了です。
まだ学習中の身です故、実務経験はありませぬが
多分、一括で何かを行う処理は

①transaction でタスクを実行
②失敗したら raise で特定
③begin & rescueで全体の対応
④原因となった箇所は個別で対応する

って感じになるんですかね。経験が無いのでまだ分かりませんが。


ってことでだいぶ長くなっちゃいましたが、今回は終了です。

終わり!!!!!!!!!!!!!!!!!!!!!!!!

この記事が気に入ったらサポートをしてみませんか?