RailsのWebアプリにStripeを組み込んでみた

この記事は[ソニックガーデン 若手プログラマ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sonicgarden-junior)の8日目の記事です。

 ## はじめに
以前、Ruby on Railsを使ってECサイトを模倣したwebアプリケーションを作成しました。

とはいえ、ECサイトとしては何か物足りない…と思っていたため、Stripeでオンライン決済機能を組み込んでみました。ここでは学んだことを備忘録として残しつつ、皆さんに共有したいと思います。

## そもそもStripeって何？

Stripeはオンライン決済を簡単かつ安全に導入できる決済サービスです。

個人的にはドキュメントや関連資料など情報豊富な点がかなり強いと思います。Stripeの[公式ドキュメント](https://docs.stripe.com/)はかなり読みやすいので、開発前に一読することをお勧めします！

## Stripeの仕組みはどうなっているの？

まず、Stripeを使用した決済の仕組みを大まかに把握しましょう。

StripeにはStripe Checkoutというサービスがすでに用意されており、これを使ってオンライン決済を実装すると便利です。

以下の説明および概要図は、[こちら](https://docs.stripe.com/payments/checkout/how-checkout-works?locale=ja-JP)を参照しています。詳細はそちらを確認してください。

1. ユーザーがアプリケーション上の「決済ボタン」をクリックする
2. クライアントからアプリケーションサーバーに向けて支払い情報が送信される
3. アプリケーションサーバーからStripe APIに向けてcheckoutセッションが作成される
    1. このcheckoutセッションは、ユーザーがアプリケーション上からStripeが用意する決済画面にリダイレクトする際必要なURLを提供する
4. リダイレクト先の決済画面で、必要情報を入力し送信する
5. 4を持って取引が完了し、ユーザーはアプリケーション画面に遷移する

![CleanShot 2024-12-07 at 15.39.14@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3927131/e0c81326-139c-9c8d-1da9-8b17752815aa.png)


複雑なことは一切なくシンプルな仕組みです。

## どうやって実装するの？

すでにサービスの注文機能まで実装完了している状態から進めていきます。

簡単なERとしては以下の通りです。
![CleanShot 2024-12-07 at 17.45.04@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3927131/ecf796bb-5a69-f918-5032-617d86d82094.png)


コード中にcurrent_cart, current_userという変数が登場しますが、current_cart = カート内商品を含むカート情報、current_user = 現在ログイン中のユーザーのことを指しています。

まずはStripeのAPIを利用する準備をします。

1. StripeのAPIキーを取得する
    1. Stripeに新規登録
        a. https://dashboard.stripe.com/register
    2. 新規登録できたらダッシュボードにアクセス
        a. 公開可能キーとシークレットキーを取得する
2. credentialsにキーを登録する
    ```ruby
    EDITOR="vi" bin/rails credentials:edit -e development
    ```
    
3. config/initializersにStripe.rbを作成する  
    ```ruby
    Stripe.api_key = Rails.application.credentials.dig(:Stripe, :secret_key)
    Stripe.api_version = '2024-10-28.acacia' #ここはドキュメントを読み最新のバージョンにしてください
    ```
4. サーバーを再起動する

次に決済処理の実装です。

1. gem をインストールする
    a. [https://github.com/Stripe/Stripe-ruby](https://github.com/stripe/stripe-ruby)
    
    ```ruby
    gem install stripe
    ```
    
2. `checkouts_controller.rb`を作成
    
    ```ruby
    rails g controller checkouts
    ``` 
    
3. routesの設定
    
    ```ruby
    resources :checkouts, only: %i[create]
    ```
    
4. `checkouts_controller.rb`の中身を作成
    
    ```ruby
    class CheckoutsController < ApplicationController
      def create
        line_items = current_cart.line_items_checkouts
        session = create_session(line_items)
        redirect_to session.url, allow_other_host: true
      end
    
      private
    
      def create_session(line_items)
       Stripe::Checkout::Session.create(
          client_reference_id: current_user.id,
          customer_email: current_user.email,
          mode: 'payment',
          payment_method_types: ['card'],
          line_items:,
          shipping_address_collection: {
            allowed_countries: ['JP'],
          },
          shipping_options: [
            {
              shipping_rate_data: {
                type: 'fixed_amount',
                fixed_amount: {
                  amount: 500,
                  currency: 'jpy',
                },
                display_name: '全国一律',
              }
            }
          ],
          success_url: root_url,
          cancel_url: "#{root_url}cart"
        )
      end
    end
    
    ```
    
    a. `create`アクションで、checkoutセッションを作成しています。
    b. `create_session`では、必要なparameterを渡しています。詳細は[こちら](https://docs.stripe.com/api/checkout/sessions/create)をご覧ください
5. `app/models/cart.rb`に、商品情報を返すメソッドを記述 
    
    ```ruby
    class Cart < ApplicationRecord
    
      belongs_to :user
      has_many :cart_items, dependent: :destroy
      has_many :books, through: :cart_items
      
      
      def line_items_checkouts
    
        cart_items.map do |cart_item|
          {
            quantity: 1,
            price_data: {
              currency: 'jpy',
              unit_amount: cart_item.book.price,
              product_data: {
                name: cart_item.book.title,
                metadata: {
                  product_id: cart_item.book_id,
                },
              },
            },
          }
        end
      end
    end
    ```
    
6. viewに決済ボタンを配置
    
    ```ruby
    button_to '注文する', checkouts_path, method: :post, class: 'btn btn-outline-danger', data: { turbo: false, turbo_confirm: '決済を進めますか？' }
    ```
    

1. ここまで実装できたら、ボタンをクリックして画面遷移するか確かめてみましょう。
    
    a. こんな画面が見えたら成功です！
    ![CleanShot 2024-12-07 at 18.02.41@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3927131/6ffcc6fd-6d78-a5b3-57b7-87ca75bd5c0d.png)

    
    決済までテストするためにはこの[ドキュメント](https://docs.stripe.com/testing?locale=ja-JP)が参考になります。
    
    テスト環境で使えるカード情報としては以下が指定されています。
    
    ```
    カード番号：4242 4242 4242 4242
    有効期限：今より未来の年月
    セキュリティーコード：任意の三桁
    ```
    

      [https://dashboard.Stripe.com/test/payments](https://dashboard.stripe.com/test/payments)から、支払いデータが作成されていたら、無事に決済完了しています。

## おわりに

以上が、Stripeを使ったオンライン決済機能の実装内容でした。
Stripeにはこれ以外にも使えるAPIがたくさんあるため、ぜひ色々試してみたいと思います。最後までお読みいただきありがとうございました。

[ソニックガーデン 若手プログラマ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sonicgarden-junior)の9日目は@ryusei1212 です。お楽しみに！