やまないエラーはない
デプロイが終わったはずなのに、まだ大きなエラーがあって、いろいろわやわやしていた。アプリでは振り返りの際に複数の目標の状態を更新したりする。複数の進行中の目標について、進行中から完了に変更させたり、期限を延ばしたりできるためだ。
複数のレコードを更新するやりかたは過去に学んだ。しかし、それがひとつでもバリデーションエラーがあったらどうなるか。今のコードではエラーが出たやつだけ保存されずに、あとは保存されてしまう。なんかいただけない。
振り返り
振り返りレコード保存OK.
関連づけられた目標達
- 目標A
状態変更終了。 進行中→完了
- 目標B
締め切り変更 →2002/1/1
バリデーションエラー:過去の日付は締め切りに設定できない
この場合、振り返りと目標Aは保存される。しかもバリデーションエラーの画面が出ない。どうしよう。
それより先にその傘をくれよ
トランザクションという概念を導入しよう。これはその中に入っている処理のうち、ひとつでも正常に処理されないと、他の全ての処理が未完に終わるものだ。銀行のお金のやりとりのシステムとか、そんなものに利用される。
Railsの場合はtransactionメソッドというのが提供されている。Railsのドキュメントにはモデルのメソッドとして記述されているが、ActiveRecord::Baseとつなげてもかける。
ActiveRecord::Base.transaction do
# 同時に行いたい処理
end
私はその中で
- ひとつのReviewレコードの新規作成・保存
- 複数のPlanレコードの更新
行っている。ひとつでもできなかったら、バリデーションエラーが出るようにしたい。
#略
def create
#略
# いろんなパラメータ設定
#略
# @plan トップページのバリデーションエラーを表示させるためのインスタンス
@plan = Plan.new
all_valid = true
ActiveRecord::Base.transaction do
all_valid &= @review.save
plan_keys.each_with_index do |id, i|
@plan_select = Plan.find(id)
if !@plan_select.update(item[i])
@plan.errors.merge!(@plan_select.errors)
all_valid = false
end
end
if !all_valid
raise ActiveRecord::Rollback
end
end
if all_valid
plan_keys.each_with_index do |id, i|
@plan = Plan.find(id)
all_valid &= @review.review_items.create!(plan_id: id)
end
end
if !all_valid
flash.now[:alert] = "投稿に失敗しました"
@plans = Plan.where(id: plan_keys)
@review_item_array = Array.new(@plans.size, ReviewItem.new)
binding.pry
render :new
else
flash[:notice] = "振り返りを投稿しました"
redirect_to action: 'index'
end
end
なにを行ったか。まず、 all_valid
は正常に動作が終了したかどうかを示すフラッグだ。 all_valid &= A
で all_valid = all_valid && A
ということをしている。
@plan.errors.merge!(@plan_select.errors)
これはエラーメッセージをひとつのインスタンスに格納している。ループで回していくと、いろんなインスタンスにいろんなエラーが格納されている。このままエラーを表示させようと思うと、view画面でちょっと面倒な記述をしないといけない。調べたらちょうど良いメソッドがあったので、これを使うことにした。
if !all_valid
raise ActiveRecord::Rollback
end
これはわざと例外を発生させて、エラーを起こさせている、、のだが本当にこれが正しい使い方なのか。ここらへんはもうちょっと勉強が必要。
あれが欲しい全て欲しい ただ虚しい
個人開発に限らず、全てのものはエラーと隣り合わせ。現実世界はエラーが表示されないこともあるので、わりと幸せな世界なのかもしれない。もうちょっと開発していこう。
トランザクションの処理を書く際に、伊藤さんの以下の記事を参考にした。が、自分の書いたものがこれで正解なのかよくわからない。テストも書かないといけないよなぁ。