はじめに
この記事の筆者はプログラミングを学習し始めたばかりの初心者です。間違いがあれば指摘していただけると幸いです。
概要
この記事はRuby on Rails6 実践ガイドを読んで学んだことを自分用のメモとして記録したものです。抜粋してピックアップするので読みづらいと思われます。すいません。
この本には、続編の機能拡張編もあり、記事を書いている段階で二冊とも学習を終えています。復習もかねて記事を書いていくつもりです。
機能拡張編のcp1とcp2は環境構築と本編のコードの説明なのでとばします。
前の記事
Ruby on Rails6 実践ガイド cp4~cp6 【メモ】
Ruby on Rails6 実践ガイド cp7~cp9 【メモ】
Ruby on Rails6 実践ガイド cp10~cp12 【メモ】
Ruby on Rails6 実践ガイド cp13~cp15 【メモ】
Ruby on Rails6 実践ガイド cp16~cp18 【メモ】
Ruby on Rails6 実践ガイド[機能拡張編] cp3~cp6 【メモ】
機能拡張編 Chapter 7 複雑なフォーム
before_validationにメソッドを指定する
before_validation :set_application_start_time
private def set_application_start_time
# ロジックは省略
end
before_validationは引数にシンボルを与えると対応するメソッドを実行します。
面白いコードも多くありましたが、汎用的な情報に切り出しにくかったのでこの章は省略します。
また読み直したいと思います。
機能拡張編 Chapter 8 トランザクションと排他的ロック
並列で走る複数の処理の結果が、順序やタイミングによって想定外の結果をもたらすことをレースコンディションといいます。
データベース処理におけるレースコンディションは、排他的ロックをうまく利用することで解決できます。
下のコードはプログラムへの申し込みを行う処理を行っています。
def accept(program)
ActiveRecord::Base.transaction do
program.lock!
if max = program.max_number_of_paticipants
if program.entries.where(canceled: false).count < max
program.entries.create!(customer: @customer)
return :accepted
else
return :full
end
else
program.entries.create!(customer: @customer)
return :accepted
end
end
end
※コントローラーの処理をサービスオブジェクトのクラスのインスタンスメソッドに移したコードです。
※returnでシンボルをコントローラーに返しています。コントローラー側では戻り値によって処理を分岐させています。
上のコードでは、最大参加者数が定義されているか、参加者数が最大に達しているかで処理を分岐させています。
最大参加者数ギリギリの状態で同時に申しこみが行われた場合、参加者数がオーバーしてしまう恐れがあります。
lock!を使うとそのオブジェクトのテーブルレコードに対して排他的ロックを取得します。排他的ロックを取得するにはトランザクションが開始されている必要があります。
transactionブロックの中で例外が発生するとすべての処理がロールバックします。データベースへの保存に失敗した場合、例外が発生するようにsave!やcreate!を使う必要があります。
機能拡張編 Chapter 9 フォームの確認画面
確認画面の実装
確認画面で更新ボタンをクリックすればデータベースに保存され、訂正ボタンをクリックすると入力フォームに戻るような確認画面を実装します。
confirmアクション
# PATCH
def confirm
@confirm_form = Customer::AccountForm.new(current_customer)
@customer_form.assign_attributes(params[:form])
if @customer_form.valid?
render action: "confirm"
else
flash.now.alert = "入力に誤りがあります。"
render action: "edit"
end
end
※Customer::AccountFormはフォームオブジェクトのクラスです。
データベースへの保存はせずにバリデーションだけ行っています。
confirmアクションのビューテンプレート
= form_with model: @customer_form, scope: "form",
url: :customer_account do |f|
= f.label :family_name
.field-value.readonly
= @customer_form.customer.send(family_name)
= f.hidden_field :family_name
= f.submit "更新"
= f.submit "訂正", name: "correct"
サーバーに送信する情報はhidden_fieldに隠してます。
updateアクション
def update
@confirm_form = Customer::AccountForm.new(current_customer)
@customer_form.assign_attributes(params[:form])
if params[:commit]
if @customer_form.save
flash.notice = "アカウント情報を更新しました。"
redirect_to :customer_account
else
flash.now.alert = "入力に誤りがあります。"
render action: "edit"
end
else
render action: "edit"
end
end
パラメーターにcommitという値がセットされているかどうかで訂正ボタンか更新ボタンのどっちが押されたのか判定しています。
= f.submit "更新"
= f.submit "訂正", name: "correct"
submitメソッドにはnameオプションを与えることができます。デフォルトではcommitです。更新ボタンが押されると"commit"というキーのパラメータが、訂正ボタンが押されると"correct"というキーのパラメータがupdateアクションにわたります。
続き
続きの記事のURLも順次追加していきます。
Ruby on Rails6 実践ガイド [機能拡張編] cp10~cp12 【メモ】
引用元
※マークダウンの引用を用いている部分は以下の書籍から引用しています。
Ruby on Rails6 実践ガイド