H30秋FE試験 問3 を RubyonRails で作ってみる

/
#資格#rails

from Qiita: H30FE試験問題3 DB問題

H30 秋 FE 試験の問 3 のコンサートに則したサイトを実際に作っていた。

Refferrence

Transaction for Payment controller

コンサートチケットの支払い時の、ポイント使用・追加あたりの、Payment コントローラ内に実装。

Transaction flow

  1. ユーザーはポイント User.point を持っている
  2. 購入時に User.point の一部/全部を支払額 Sale.amount に充てることができる
  3. 使用ポイント Sale.used_point が更新される
  4. 支払額から使用した User.point を引いたものが、決済額 Payment.amount となる
  5. 決済額 Payment.amount のうち、デフォルトの割合が付与ポイント Payment.added_point となる
  6. ユーザーのポイント残高は、支払前の User.point - Sale.used_point + Payment.added_point で更新される

支払い完了の条件

  • User.point、Sale.used_point、Payment.added_point はすべて 0 以上(>=0)
    • モデル側のバリデーション validates :point, numericality: { greater_than_or_equal_to: 0 } 利用
  • User.point >= Sale.used_point
    • False となる操作は悪意しかないので、トランザクション外の if 文で

Implement

User.point、Sale.used_point、Payment.added_point はすべて 0 以上(>=0)

undefined
1
# User model
2
validates :point, numericality: { greater_than_or_equal_to: 0 }
3
# Sale model
4
validates :used_point, numericality: { greater_than_or_equal_to: 0 }
5
# Payment model
6
validates :added_point, numericality: { greater_than_or_equal_to: 0 }
users_controller.rb
1
def payment
2
@user = # ...
3
@sale = # ...
4
@concert = # ...
5
@payment = Payment.new(sale_id: @sale.id, date: Date.current)
6
respond_to do |format|
7
if current_user.point < params_used_point
8
# 所持ポイントを超過している旨の警告文 (以下、ポイントをPと略す)
9
else # when pay with appropriate points
10
begin
11
ActiveRecord::Base.transaction do
12
if @sale.amount <= params_used_point # when using points is over sale price
13
@sale.update!(used_point: @sale.amount) # succeeded in paying
14
@payment.update(amount: 0, added_point: 0)
15
else
16
@sale.update!(used_point: params_used_point)
17
@payment.update!(amount: pay_amount, added_point: 追加P計算関数)
18
end
19
@user.update!(point: ユーザP更新関数) # completed to pay
20
end
21
rescue StandardError => e # if transaction failed
22
logger.error e
23
logger.error e.backtrace.join("\n")
24
@sale = # ...
25
@concert = # ...
26
format.html { render :confirm, notice: 'エラー' }
27
end
28
end
29
end
30
end