質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

2回答

2629閲覧

【Rails】ActiveRecord::Base.transaction do ~ end にて気になること と エラー処理に関して (エラーメッセージ)

nyako

総合スコア45

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2021/06/07 06:27

https://teratail.com/questions/342357
「 Rails API 例外処理 create! or createなのか ベストプラクティスを知りたい 」 にてご回答いただけた内容に関しての質問になります。

質問内容

1,find_byでレコードを探したいときトランザクション内にて行うのかそれともトランザクション外部で行うのか。下記のコードではトランザクション外部で書いてみたコードになります。トランザクション内で行うのであればロジックは考えます...

2,DBを操作しないメールを送信するコードもトランザクション内であるので一個のトランザクション内に書くのか。

3,上記コードのエラーを示すレスポンスに関して、 result = { error: { message: e.message } } とerrorの中に二重構造にした理由を知りたいです。
これはフロント側で何か使うために2重の構造にしているのか、調べてもあまり出てこなく、気になっております。

ruby

1# ご回答いただいた内容を参考に記述してみました。 2 3Class XXXcontroller < Applicationcontroller 4 5 def create 6 user = User.find(params[:id]) # 質問1 7 8 render json: status: 400, { message: "該当のユーザーはいません。"} if user.blank? 9 10 11 begin 12 ActiveRecord::Base.transaction do 13 user.create(...)! 14 Form.update!(is_completed: true) 15 Mailer.send_email # 質問2 16 end 17 18 render status: 200, json: { message: "会員登録に成功しました。メール送信を行いました。"} 19 20 rescue => e 21 22 result = {error: {message: e.message }} # 質問3 23 24 render status: 500, json: { result } 25 end 26 27 end 28end 29

質問1は別のやり方でも書いてみました。(トランザクション外での実装)

rescue_fromでまとめて、RecordNotFoundが出た時点でメソッド化したものを呼び出すか。

ruby

1 rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_message 2 3 user = User.find(params[:id]) 4 5 private 6 7 def render_not_found_message 8 render json: status: 400, { message: "該当のユーザーはいません。"} 9 end

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

find_byでレコードを探したいときトランザクション内にて行うのかそれともトランザクション外部で行うのか。

コードの中身次第です。純粋に1レコードしか取得しない状況でトランザクションが影響することは考えられませんが、サブテーブルが複雑に絡み合うような取得の場合はトランザクションで1時点の状態を確実に取得したほうが適当かもしれません。

DBを操作しないメールを送信するコードもトランザクション内であるので一個のトランザクション内に書くのか。

そもそも、メール送信処理をトランザクションに入れるべきではありません。メール送信のロールバックも不可能ですし、DB処理より長時間かかるメール処理の時間中もロックが続いてしまいます。デメリットしかありません。

投稿2021/06/07 06:38

maisumakun

総合スコア145201

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/06/07 06:45

RailsのActionMailerには、.deliver_laterのような遅延実行の仕掛けがあります。 アクション内からメールを生成するような場合はそれに任せるのがいいです。
nyako

2021/06/07 07:08

理解が深まりました!ご回答ありがとうございます。 2番目のご回答に関してなのですが、 DBに保存ができても、メールが送れなければ保存はしたくないのでトランザクション外となると メール送信の際エラーが発生した場合も含めたロジックはどのように記載すれば良いのでしょうか。 create! → 成功 update! → 成功 Mailer.send → メール送信失敗 の場合DBにデータが残ってしまうのが懸念点です。。
nyako

2021/06/07 07:10

コメント見落としてました!すみません。メール送信はトランザクション外にして.deliver_laterにすれば良いということですね。
guest

0

ベストアンサー

1,find_byでレコードを探したいときトランザクション内にて行うのかそれともトランザクション外部で行うのか。下記のコードではトランザクション外部で書いてみたコードになります。トランザクション内で行うのであればロジックは考えます...

トランザクションはテーブルの更新処理に対して成功 or 失敗を担保するための仕組みですので、
単なる検索でトランザクションが必要かどうかはケースバイケースになります。

2,DBを操作しないメールを送信するコードもトランザクション内であるので一個のトランザクション内に書くのか。

トランザクションはDBに関する話なので、メールを送るだけならトランザクションである必要はありません。
もちろんトランザクション内に書いても処理の順番が正しければ意図通りに動きます。

今回提示されているコードに関してはcreate!(), update!()の後にメール送信を書いているので、
成功した時しかメール送信処理に来ないため、保存に失敗したのにメールが飛ぶといった事はありません。
(ビックリマーク付きのメソッドを使っているため、保存に失敗したら例外が発生するため)

でも、明確にトランザクションとメール送信は分けたほうがコードとしては分かりやすいです。

3,上記コードのエラーを示すレスポンスに関して、 result = { error: { message: e.message } } とerrorの中に二重構造にした理由を知りたいです。 これはフロント側で何か使うために2重の構造にしているのか、調べてもあまり出てこなく、気になっております。

{ error: { message: "エラー" } }

というハッシュを返しているので、フロント側では例えば、dataという変数にレスポンスを受け取ったとしたらdata.error.messageとして使う事を想定しているだけです。

投稿2021/06/07 06:50

編集2021/06/07 07:10
mingos

総合スコア4032

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nyako

2021/06/07 07:56

ご回答頂きありがとうございます!よく理解が出来ました。 最後に1つ、メール送信の際 トランザクション内に create! update!して トランザクション外にメール送信をする実装をすると DBに保存が成功 + メール送信に失敗となった場合、やっぱりcreate! update!した保存を取り消すのは難しいですよね...?
mingos

2021/06/07 08:34

そうですね。取り消せません。 特にトランザクション内でメール送信を書いたとしても、 ロールバックされる条件は例外の発生なので、メール送信に失敗した時に例外が発生しない場合は取り消せません。 確実にメール送信失敗時に例外が発生するのかどうかは自分も分かりません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問