| 36 |ページネーションの実装 << [ホーム] >> | 38 | Stripe Connectの実装
Stripe(ストライプ)を使ってでクレジット決済ができるようにします。
まずは以下の手順でStripeのアカウントを取得してください。
mrradiology.hatenablog.jp
ダッシュボードで「公開可能キー」と「シークレットキー」をコピーします。
記述追加 GemFile(89行目)
# stripe gem 'stripe', '=4.18.1'
GemFile
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.6.6' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main' gem 'rails', '~> 6.0.4', '>= 6.0.4.7' # Use postgresql as the database for Active Record gem 'pg', '>= 0.18', '< 2.0' # Use Puma as the app server gem 'puma', '~> 4.1' # Use SCSS for stylesheets gem 'sass-rails', '>= 6' # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker', '~> 4.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Active Storage variant # gem 'image_processing', '~> 1.2' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.4.2', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '~> 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of web drivers to run system tests with browsers gem 'webdrivers' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] # デバイス gem 'devise' # Rubyバージョンエラー修正 gem "net-http" # 日本語化 gem 'rails-i18n' # アマゾンS3 gem 'aws-sdk', '~> 3' # アクションテキスト画像表示 gem "mini_magick" gem 'image_processing', '~> 1.2' #googleマップ gem 'geocoder', '~> 1.4' # facebook認証 gem 'omniauth', '= 1.9.0' gem 'omniauth-facebook', '= 5.0.0' # google認証 gem 'omniauth-google-oauth2' # 検索 gem 'ransack', '~> 2.3' # ページネーション gem 'kaminari', '~> 1.2', '>= 1.2.1' gem 'bootstrap5-kaminari-views', '~> 0.0.1' # stripe gem 'stripe', '=4.18.1'
コマンド
bundle update
ユーザテーブルにStripeのカラムを追加します。
コマンド
rails g migration AddStripeToUser stripe_last_4 stripe_id
コマンド マイグレーション適用
rails db:migrate
「config\initializers」フォルダに「stripe.rb」ファイルを新規作成してください。
config\initializers\stripe.rb(新規作成したファイル)
ご自分の公開可能キーとシークレットキーを入れて下さい
Rails.configuration.stripe = { #ご自分の公開可能キーとシークレットキーを入れて下さい :publishable_key => 'ご自分の公開可能キーを入れてください。', :secret_key => 'ご自分のシークレットキーを入れてください' } Stripe.api_key = Rails.configuration.stripe[:secret_key] Stripe.api_version = '2020-03-02'
「app\views\users」フォルダに「payment.html.erb」ファイルを新規作成して下さい。
app\views\users\payment.html.erb(新規作成したファイル)
<style> .StripeElement { box-sizing: border-box; height: 40px; padding: 10px 12px; border: 1px solid transparent; border-radius: 4px; background-color: white; box-shadow: 0 1px 3px 0 #e6ebf1; -webkit-transition: box-shadow 150ms ease; transition: box-shadow 150ms ease; } .StripeElement--focus { box-shadow: 0 1px 3px 0 #cfd7df; } .StripeElement--invalid { border-color: #fa755a; } .StripeElement--webkit-autofill { background-color: #fefde5 !important; } </style> <div class="row" style="margin-left: 10rem;"> <div class="col-sm-8"> <br/> <div class="card text-center"> <% if current_user.stripe_id? %> <h4 class="card-header text-center bg-primary text-light"> <span style="font-size: 1.3rem;"><i class="far fa-credit-card"></i> クレジットカード更新</span> <% if current_user.stripe_last_4 %> <span style="font-size: 1rem;"><%= "(登録カード: **** **** **** #{current_user.stripe_last_4})" %></span> <% end %> <% else %> <h4 class="card-header text-center bg-primary text-light"> <span style="font-size: 1.3rem;"><i class="far fa-credit-card"></i>クレジットカード登録</span> <% if current_user.stripe_last_4 %> <span style="font-size: 1rem;"><%= "(**** **** **** #{current_user.stripe_last_4})" %></span> <% end %> <% end %> </h4> <div style="margin: 50px; text-align: left;"> <br/> <br/> [対応カード]<br> </p> <br/> <%= form_with url: update_payment_path, local: true, id: "payment-form" do |f| %> <div id="card-element"> <!-- ストライプ要素がここに挿入されます。 --> </div> <!-- フォームのエラーを表示するために使用されます。 --> <div id="card-errors" role="alert"></div> <br/> <br/> <%= f.submit "#{current_user.stripe_id ? "カードを更新する" : "カードを追加する"}", class: "btn btn-outline-danger btn-block rounded-pill" %> <% end %> <br/> <br/> <span style="font-size: 0.8rem;">CVCとは、クレジットカードの裏面に記載されている暗証番号です。<br/> ほとんどのカード(Visa、MasterCardなど)ではカード裏面の署名欄に記載されています。<br/> 記載番号の最後の3ケタがこれにあたります。<br/> American Express(AMEX)カードでは通常、カード前面の4ケタのコードとなります。</span><br/><br/> </div> </div> </div> </div> <script src="https://js.stripe.com/v3/"></script> <script> // Stripeクライアントを作成します。 var stripe = Stripe('<%= Rails.configuration.stripe[:publishable_key] %>'); // Elementsのインスタンスを作成します。 var elements = stripe.elements(); // Elementの作成時に、カスタムスタイリングをオプションに渡すことができます。 var style = { base: { color: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } }; // カード要素のインスタンスを作成します。 var card = elements.create('card', {style: style}); // カード要素のインスタンスを `card-element` <div>に追加します。 card.mount('#card-element'); // カード要素からのリアルタイム検証エラーを処理します。 card.addEventListener('change', function(event) { var displayError = document.getElementById('card-errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } }); // フォームの送信を処理します。 var form = document.getElementById('payment-form'); form.addEventListener('submit', function(event) { event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // エラーが発生したかどうかをユーザーに通知します。 var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // トークンをサーバーに送信します。 stripeTokenHandler(result.token); } }); }); // トークンIDを使用してフォームを送信します。 function stripeTokenHandler(token) { // トークンIDをフォームに挿入して、サーバーに送信されるようにします var form = document.getElementById('payment-form'); var hiddenInput = document.createElement('input'); hiddenInput.setAttribute('type', 'hidden'); hiddenInput.setAttribute('name', 'stripeToken'); hiddenInput.setAttribute('value', token.id); form.appendChild(hiddenInput); // フォームを送信する form.submit(); } </script>
ルートを設定します。
「config\routes.rb」ファイルに以下の記述を追加します。
1.記述追加 config\routes.rb(13行目)
get 'settings/payment', to: 'users#payment', as: 'settings_payment'
2.記述追加 config\routes.rb(16行目)
post '/settings/payment', to: 'users#update_payment', as: "update_payment"
config\routes.rb
Rails.application.routes.draw do # ルートを app\views\pages\home.html.erb に設定 root 'pages#home' get 'pages/home' get '/dashboard', to: 'users#dashboard' get '/users/:id', to: 'users#show', as: 'user' get '/your_trips' => 'reservations#your_trips' get '/your_reservations' => 'reservations#your_reservations' get 'search' => 'pages#search' get '/host_calendar' => "calendars#host" get 'settings/payment', to: 'users#payment', as: 'settings_payment' post '/users/edit', to: 'users#update' post '/settings/payment', to: 'users#update_payment', as: "update_payment" devise_for :users, path: '', path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'}, controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'} resources :rooms, except: [:edit] do member do get 'listing' get 'pricing' get 'description' get 'photo_upload' get 'amenities' get 'location' get 'preload' get 'preview' delete :delete_photo post :upload_photo end resources :reservations, only: [:create] end resources :guest_reviews, only: [:create, :destroy] resources :host_reviews, only: [:create, :destroy] resources :reservations, only: [:approve] do member do post '/approve' => "reservations#approve" end end # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end
「app\controllers\users_controller.rb」ファイルに以下の記述を追加します。
記述追加 app\controllers\users_controller.rb(33行目)
def update_payment if !current_user.stripe_id customer = Stripe::Customer.create( email: current_user.email, source: params[:stripeToken] ) else customer = Stripe::Customer.update( current_user.stripe_id, source: params[:stripeToken] ) end if current_user.update(stripe_id: customer.id, stripe_last_4: customer.sources.data.first["last4"]) flash[:notice] = "新しいカード情報が登録されました" else flash[:alert] = "無効なカードです" end redirect_to request.referrer rescue Stripe::CardError => e flash[:alert] = e.message redirect_to request.referrer end
app\controllers\users_controller.rb
class UsersController < ApplicationController before_action :authenticate_user! def dashboard @user = current_user @rooms = @user.rooms @guest_reviews = Review.where(type: "GuestReview", host_id: @user.id) # ユーザーがゲストの場合、ユーザに対するすべてのホストレビューを表示 @host_reviews = Review.where(type: "HostReview", guest_id: @user.id) end def show @user = User.find(params[:id]) @rooms = @user.rooms # ユーザーがホストの場合、ホストに対するすべてのゲストレビューを表示 @guest_reviews = Review.where(type: "GuestReview", host_id: @user.id) # ユーザーがゲストの場合、ユーザに対するすべてのホストレビューを表示 @host_reviews = Review.where(type: "HostReview", guest_id: @user.id) end def update @user = current_user if @user.update_attributes(current_user_params) flash[:notice] = "保存しました" else flash[:alert] = "更新できません" end redirect_to dashboard_path end def update_payment if !current_user.stripe_id customer = Stripe::Customer.create( email: current_user.email, source: params[:stripeToken] ) else customer = Stripe::Customer.update( current_user.stripe_id, source: params[:stripeToken] ) end if current_user.update(stripe_id: customer.id, stripe_last_4: customer.sources.data.first["last4"]) flash[:notice] = "クレジットカードが登録されました" else flash[:alert] = "無効なカードです" end redirect_to request.referrer rescue Stripe::CardError => e flash[:alert] = e.message redirect_to request.referrer end private def current_user_params params.require(:user).permit(:about, :status, :avatar) end end
ナビゲーションバーのリンクを追加します。
「app\views\shared\_navbar.html.erb」ファイルに以下の記述を追加します。
記述追加 app\views\shared\_navbar.html.erb(68行目)
<span class="dropdown-item"><i class="far fa-credit-card"></i><%= link_to 'クレジットカード登録', settings_payment_path, class: "btn btn-white", data: { turbolinks: false} %></span>
app\views\shared\_navbar.html.erb
<nav class="navbar navbar-expand-lg navbar-dark bg-info" style="z-index: 5;"> <a class="navbar-brand" href="/"><h1 class="navh1">MinpakuBs</h1></a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown"> <ul class="navbar-nav"> <!-- もしログインしていなかったら--> <% if (!user_signed_in?) %> <li class="nav-item" style="margin-right: 20px; margin-bottom: 5px;"> <%= link_to "新規ユーザ登録", new_user_registration_path, class: "btn btn-light" %> </li> <li class="nav-item"> <%= link_to "ログイン", new_user_session_path, class: "btn btn-light", style: "margin-right: 80px;" %> </li> <!-- ログインしていたら --> <% else %> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <figure class="avatar <%= current_user.status ? "online" : "offline" %>"></figure> <%= image_tag avatar_url(current_user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 40px; height: 30px;" %> <%= current_user.full_name %> </a> <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <span class="dropdown-item"><i class="fas fa-user-edit"></i><%= link_to "ユーザ登録情報編集", edit_user_registration_path, class: "btn btn-white" %></span> <hr/> <span class="dropdown-item"><i class="fas fa-sign-out-alt"></i><%= link_to "ログアウト", destroy_user_session_path, method: :delete, class: "btn btn-white" %></span> </div> </li> <% end %> </ul> </div> </nav> <% if (user_signed_in?) %> <nav class="navbar navbar-expand-lg navbar-light bg-light" style="z-index: 4;"> <div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown"> <ul class="navbar-nav mr-auto"> <li class="nav-item" style="margin-left: 100px; margin-bottom: 5px; margin-right: 80px;"> <span style="margin-top:13px;"><i class="fas fa-tachometer-alt"></i></span><%= link_to 'ダッシュボード', dashboard_path, class: "btn btn-light" %> </li> <li class="nav-item dropdown" style="margin-right: 50px;"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-hospital-symbol"></i> ホスト </a> <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <span class="dropdown-item"><i class="fas fa-edit"></i></i><%= link_to "お部屋を新規登録", new_room_path, class: "btn btn-white" %></span> <span class="dropdown-item"><i class="far fa-list-alt"></i><%= link_to "登録したお部屋一覧", rooms_path, class: "btn btn-white" %></span> <span class="dropdown-item"><i class="far fa-list-alt"></i><%= link_to "受注予約の管理", your_reservations_path, class: "btn btn-white" %></span> </div> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-user-friends"></i> ゲスト </a> <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <span class="dropdown-item"><i class="far fa-list-alt"></i><%= link_to "ご予約の確認", your_trips_path, class: "btn btn-white" %></span> <span class="dropdown-item"><i class="far fa-credit-card"></i><%= link_to 'クレジットカード登録', settings_payment_path, class: "btn btn-white", data: { turbolinks: false} %></span> </div> </li> </ul> </div> </nav> <% end %>
ブラウザ確認
http://localhost:3000/settings/payment
テストカードは「4242 4242 4242 4242」を使用して下さい。
あとの情報は何でも大丈夫です。
登録すると下4ケタが表示されます。
ユーザテーブルにStripeのIDが格納されます。
Stripeのダッシュボードで「顧客」を見ると登録されているのが確認できます。
↓↓クリックして頂けると励みになります。