はじめに
個人アプリにて、クレジットカード決済を行うため、PAY.JPを導入しました。
機能実装に関して、備忘録として記載しています。
前回の記事
PAY.JPでクレジットカードの登録・削除機能を実装する
前提条件
- Rails 5.2.4.2
- Ruby 2.5.1
- devise使用
- haml使用
- VSCode使用
前回までにカード情報の登録を行うためCardモデル及びCardコントローラーを作成しました。
今回は新たに購入用モデル及びコントローラーを作成して購入処理を行っていきます。
手順
- モデルの作成
- テーブルの作成
- コントローラーの作成
モデルの作成
今回はOrderモデルを作成していきます。
class Order < ApplicationRecord
belongs_to :user
has_many :products, through: :order_details
has_many :order_details, dependent: :destroy
belongs_to :card
belongs_to :address
enum postage: {burden: 0, free: 1}
enum status: {支払済み: 0, 配送準備中: 1, 配送済み: 2}
def add_items(cart)
cart.line_items.target.each do |item|
item.cart_id = nil
line_items << item
end
end
end
ECサイトを作成したので、カート機能などを実装している関係で、インスタンスメソッドなど定義しておりますが、今回は購入機能にフォーカスしているため、割愛します。
なので、belongs_to :cardの1行が使いたい部分になります。
テーブルの作成
マイグレーションファイルを以下のようにします。
class CreateOrders < ActiveRecord::Migration[5.2]
def change
create_table :orders do |t|
t.references :user, foreign_key: true
t.references :address, foreign_key: true
t.references :card, foreign_key: true
t.references :product, foreign_key: true
t.integer :quantity, null: false
t.integer :status, default: 0, null: false
t.integer :postage, default: 0, null: false
t.integer :price, null: false
t.timestamps
end
end
end
cardを外部キーとして設置しています。
コントローラーの作成
Orderコントローラーを作成していきます。
今回はnewとcreateの2つのアクションを使用します。
class OrdersController < ApplicationController
before_action :set_cart
before_action :user_signed_in
before_action :set_user
before_action :set_card
before_action :set_address
require "payjp"
#注文入力画面
def new
@line_items = current_cart.line_items
@cart = current_cart
if @cart.line_items.empty?
redirect_to current_cart, notice: "カートは空です"
return
end
if @card.present?
customer = Payjp::Customer.retrieve(@card.customer_id)
default_card_information = customer.cards.retrieve(@card.card_id)
@card_info = customer.cards.retrieve(@card.card_id)
@exp_month = default_card_information.exp_month.to_s
@exp_year = default_card_information.exp_year.to_s.slice(2,3)
customer_card = customer.cards.retrieve(@card.card_id)
@card_brand = customer_card.brand
case @card_brand
when "Visa"
@card_src = "icon_visa.png"
when "JCB"
@card_src = "icon_jcb.png"
when "MasterCard"
@card_src = "icon_mastercard.png"
when "American Express"
@card_src = "icon_amex.png"
when "Diners Club"
@card_src = "icon_diners.png"
when "Discover"
@card_src = "icon_discover.png"
end
@order = Order.new
end
end
#注文の登録
def create
unless user_signed_in?
redirect_to cart_path(@current_cart), notice: "ログインしてください"
return
end
@purchaseByCard = Payjp::Charge.create(
amount: @cart.total_price,
customer: @card.customer_id,
currency: 'jpy',
card: params['payjpToken']
)
@order = Order.new(order_params)
@order.add_items(current_cart)
if @purchaseByCard.save && @order.save!
OrderDetail.create_items(@order, @cart.line_items)
flash[:notice] = '注文が完了しました。マイページにて注文履歴の確認ができます。'
redirect_to root_path
else
flash[:alert] = "注文の登録ができませんでした"
redirect_to action: :new
end
end
private
def order_params
params.permit(:user_id, :address_id, :card_id, :quantity, :price)
end
def set_user
@user = current_user
end
def set_cart
@cart = current_cart
end
def set_card
@card = Card.find_by(user_id: current_user.id)
end
def set_address
@address = Address.find_by(user_id: current_user.id)
end
def user_signed_in
unless user_signed_in?
redirect_to cart_path(@cart.id), alert: "レジに進むにはログインが必要です"
end
end
end
newアクションにおいては、購入確認ページの形態をとっています。
ユーザーが登録していないと、そもそも購入確認ページに訪問できない仕様になっております。
かつ、ユーザーがマイページでカードを登録できるように仕様です。
購入確認ページで初めてカード登録を行う仕様にするのであれば、前回の記事で作成したCardコントローラーのnewアクションのインスタンス変数を持ってこればいいかもですね。
createアクションでは以下の内容が必要です。
見易いように内容抽出しております。
def create
@purchaseByCard = Payjp::Charge.create(
amount: @cart.total_price,
customer: @card.customer_id,
currency: 'jpy',
card: params['payjpToken']
)
if @purchaseByCard.save
flash[:notice] = '注文が完了しました。'
redirect_to root_path
else
flash[:alert] = "注文の登録ができませんでした"
redirect_to action: :new
end
end