採用担当者さんはお忙しいだろうけど、
どうしても決済機能
を導入したい!
そんな方に見てほしい記事です!
この記事では、かんたん決済機能
の実装方法について解説しています。
ここで言うかんたん決済機能
とは、
ワンクリックで決済「したことにする」
という機能です。
ポートフォリオへの実装を想定しています。
一つだけ注意点があります。
この記事の方法では、Payjpなどの外部APIには決済履歴
は残りません。
(token
をダミーとして生成するためです)
参考になれば幸いです。
前提
注意:この記事ではクレジット決済は実装しません!
開発環境
・ruby 2.6.5
・Rails 6.0.3.3
完成イメージ

金額とカード情報を入力すると決済できます。
今回は、未入力で決済できる「簡単ギフト」ボタンを実装します!
(注意! この記事の方法では、外部APIには決済履歴は保存されません!)
ここでいうギフト
とは、
誰かが、誰かにお金を送る。
という意味です。
AさんがBさんに500円送った。
みたいな感じです!
ER図
ギフトに必要な2つのテーブルです
・usersテーブル
・giftsテーブル
各カラムについては、後ほど説明します。
実装の流れ
①user, giftモデル、テーブルの作成
②ルーティングを設定
③アソシエーションを書く
④giftsコントローラーにアクションを定義
⑤ビューにリンクを設置
①user, giftモデル、テーブルの作成
userモデルのマイグレーションを編集
userモデルは、devise
で作成しています。
devise
は導入していなくても大丈夫です!
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :nickname, null: false
t.string :email, null: false, default: ""
#省略
end
#省略
end
end
usersテーブルには、nickname
とemail
のカラムを用意しています。
giftモデルのマイグレーションを編集
class CreateGifts < ActiveRecord::Migration[6.0]
def change
create_table :gifts do |t|
t.references :user, foreign_key: true
t.references :giver, foreign_key: { to_table: :users }
t.integer :price, null: false
t.timestamps
end
end
end
giftsテーブルには、user
, giver
, price
という3つのカラムを用意しています。
それぞれ、
user
→ギフトを受け取る人
giver
→ギフトを送る人
price
→ギフトの金額
というデータを保存しています。
今回の決済では、ユーザー同士で行います。
一人のuserは複数のuserにギフトできます。
そのため、__usersテーブル同士で「多対多」の関係__を作る必要があります。
今回は、giftsテーブル
を中間テーブルとして作成します。
したがって、giftsテーブル
は、以下のように2つの役割を持っています。
・ギフト情報を管理
・usersテーブルと対応する中間テーブル
少し分かりづらいと思うので、
後ほど、アソシエーションを記述する時にしっかり説明します!
つづいて、giver
のオプションについて説明します。
giver
は、外部キーとして設定しています。
しかし、giver
というテーブルは存在しません!
そこで「usersテーブルから参照してね!」
と、教えてあげる必要があります。
そのためオプションに、foreign_key: { to_table: :users }
と書いています。
②ルーティングを設定
Rails.application.routes.draw do
resources :users, only: [:edit, :update, :show] do
member do
post 'easygift', to: 'gifts#easy_gift'
end
end
end
かんたん決済のための、ルーティングを記述します。
pathには、easygift
と命名していますが、ここは好きな名前で大丈夫です。
アクション名も自由に決めてOKです。
③アソシエーションを書く
userモデル
class User < ApplicationRecord
has_many :gifts
has_many :receivers, through: :gifts, source: :giver
has_many :reverse_of_gifts, class_name: 'Gift', foreign_key: 'giver_id'
has_many :giftings, through: :reverse_of_gifts, source: :user
end
userモデルのアソシエーションについて解説します。
大きく2つに分かれています。
1, 2行目が、giver
を参照するための記述
3, 4行目が、user
の参照するための記述
まず、1, 2行目について説明します。
has_many :gifts
は、2行目の為の記述です。
2行目ですが、一つずつ順番に説明していきます。
has_many :receivers, through: :gifts, source: :giver
receivers
は、架空のモデルです。
なぜ架空のモデルを作るのかについては、後ほど説明します!
through: :gifts
は、giftsテーブルを経由して、
source: :giver
は、
「giver
を参照してね!」という意味合いです。
まとめると、1, 2行目では、
giftsテーブルのgiver
を参照してね!
ということをやっています!
もう少しついてきてください!
次に、3, 4行目について説明します。
3行目ですが、これまた長いので、一つずつ順番に説明していきます。
has_many :reverse_of_gifts, class_name: 'Gift', foreign_key: 'giver_id'
reverse_of_gifts
も、架空のモデルです。
class_name: 'Gift'
は、
「reverse_of_gifts
って言ったけど、実はgiftモデルのことなんだ笑」っていう感じです。
foreign_key: 'giver_id'
は、
「giver_id
を参照して!」って意味になります。
4行目も、一つずつ見ていきます。
has_many :giftings, through: :reverse_of_gifts, source: :user
has_many :giftings
も、架空のモデルです。
through: :reverse_of_gifts
は、reverse_of_gifts
テーブルを経由して、
source: :user
は、
「user
を参照してね!」という意味合いです。
やっていることは2行目と同じです。
まとめると、3, 4行目では、
giftsテーブルのuser
を参照してね!
ということをやっています!
さて、「なぜ架空のモデルを作るのか!」について解説します!
結論から言うと、
__アソシエーションの区別がつかなくなってしまうから__です!
その理由について解説します。
まず、それぞれのアソシエーションの最初の方だけに注目しましょう。
has_many :gifts
has_many :receivers
has_many :reverse_of_gifts
has_many :giftings
これだと、別々のモデルを参照してるように見えますね。
続いて、仮に架空のモデルを作らなかった場合
の記述をしていきます。
class User < ApplicationRecord
has_many :gifts
has_many :users, through: :gifts, source: :giver
has_many :gifts, foreign_key: 'giver_id'
has_many :users, through: :gifts, source: :user
end
すると、
giftsテーブルを中間テーブルとするアソシエーションが、 2パターン記述されている
ことが分かります。
先ほどと同じように、それぞれのアソシエーションの最初の方だけに注目しましょう。
class User < ApplicationRecord
has_many :gifts
has_many :users
has_many :gifts
has_many :users
end
って、どれがどれやねぇぇぇん!
もうおわかりでしょうか。
架空のモデルを記述しない場合、
アソシエーションの区別がつかなくなってしまいます。
そうなることを防ぐために、架空のモデルを設けています!
giftモデル
class Gift < ApplicationRecord
belongs_to :user
belongs_to :giver, class_name: 'User'
attr_accessor :token
validates :user_id, presence: true
validates :giver_id, presence: true
validates :price, presence: true
validates :token, presence: true
end
giver
のオプションclass_name: 'User'
は、「userモデルを参照してください!」という意味です。
バリデーションも設定しています。
④giftsコントローラーにアクションを定義
かんたん決済のアクションを記述します。
class RoomsController < ApplicationController
#省略
def easy_gift
reciver = User.find(params[:id])
gift = Gift.create(
price: 500,
user_id: reciver.id,
giver_id: current_user.id,
token: 'dummy'
)
redirect_to root_path
end
#省略
end
本記事では、実際のカード決済の記述は割愛します。
参考資料 : payjp/payjp-ruby
easy_gift
は、ルーティングで定義したアクション名です。
gift = Gift.create(...)
の中で、各キーにバリューをセットしています。
ここで、注目してほしいのが、token: 'dummy'
です。
他のカラムとは違い、token
はテーブルに保存しません。
「じゃあ、token
に値渡さなくて良くない?」
そう思った方、、、私もそう思いました笑
しかし思い出してください!モデルの記述を!
class Gift < ApplicationRecord
belongs_to :user
belongs_to :giver, class_name: 'User'
attr_accessor :token
validates :user_id, presence: true
validates :giver_id, presence: true
validates :price, presence: true
validates :token, presence: true # 👈tokenにバリデーションの設定している!
end
token
には、presence: true
というバリデーションを設定しています。
そのため、ギフトを生成する際に、token
が無かったら、
バリデーションエラーとなり、ギフトはレコードとして保存されません。
そのため、ダミーのtoken
を用意する必要があります。
今回は、token
にバリュー 'dummy'
を渡しています。
肝心なのは、バリデーションエラーにならないように工夫することです。
さて、これでコントローラーの記述は完了です。
最後に、ビューへかんたん決済のリンクを設置します。
⑤ビューにリンクを設置
<%= link_to '簡単ギフト', easygift_user_path(@reciver), method: :post %>
ボタンを表示させたいビューに、リンクを設置します。
pathは、ターミナルでrails routes
コマンドを使って探します。
% rails routes
Prefix Verb URI Pattern Controller#Action
easygift_user POST /users/:id/easygift(.:format) gifts#easy_gift
pathは、コントローラー名とアクション名と対応しています。
また、URI Pattern
を見ると、id
を引数として渡す必要があると分かります。
これは、ルーティングをusers
にネストしているためです。
このアプリでは、id
と対応している、@reciver
を引数として渡しています。

これで実装完了です。
最後までお付き合いいただきありがとうございました!