Firestore でのセッション処理

多くのアプリには、認証設定とユーザー設定用のセッション処理が必要です。Sinatra には、この機能を実行するためのメモリベースの実装が付属しています。ただし、記録されるセッションがインスタンス間で異なる場合があるため、この実装は複数のインスタンスから提供できるアプリには適していません。このチュートリアルでは、App Engine でセッションを処理する方法を示します。

目標

  • アプリを作成する。
  • アプリをローカルで実行する。
  • App Engine にアプリをデプロイする。

費用

このドキュメントでは、課金対象である次の Cloud de Confiance by S3NSコンポーネントを使用します。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. In the Cloud de Confiance console, on the project selector page, select or create a Cloud de Confiance project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Cloud de Confiance project.

  3. Enable the Firestore API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  4. 開発環境を準備します

プロジェクトの設定

  1. ターミナル ウィンドウで、選択したディレクトリに移動し、sessions という名前の新しいディレクトリを作成します。このチュートリアルのコードはすべて、sessions ディレクトリ内にあります。

  2. sessions ディレクトリに移動します。

    cd sessions
    
  3. Gemfile を初期化します。

    bundle init
    
  4. 結果の Gemfile に次を追加します。

    gem "google-cloud-firestore", "~> 2.0"
    gem "sinatra", "~> 2.0"

    Gemfile には App Engine で読み込む必要のある、非標準の Ruby ライブラリが列挙されています。

    • google-cloud-firestore は、Firestore API の Ruby クライアントです。

    • Sinatra は、アプリ用に使用される Ruby ウェブフレームワークです。

  5. 依存関係をインストールします。

    bundle install
    

ウェブアプリの作成

このアプリは、ユーザーごとに異なる言語で挨拶を表示します。リピーターは常に同じ言語で挨拶されます。

  • テキスト エディタを使用して、sessions ディレクトリに次の内容の app.rb というファイルを作成します。

    require "sinatra"
    
    require_relative "firestore_session"
    
    use Rack::Session::FirestoreSession
    
    set :greetings, ["Hello World", "Hallo Welt", "Ciao Mondo", "Salut le Monde", "Hola Mundo"]
    
    get "/" do
      session[:greeting] ||= settings.greetings.sample
      session[:views] ||= 0
      session[:views] += 1
      "<h1>#{session[:views]} views for \"#{session[:greeting]}\"</h1>"
    end

セッション ストアの作成

アプリでユーザーの設定を保存するには、現在のユーザーに関する情報をセッションに保存する方法が必要です。次の図は、Firestore が App Engine アプリ用のセッションを処理する方法を示しています。

アーキテクチャの図: ユーザー、App Engine、Firestore。

Sinatra には、セッション データを Cookie に保存するサポートが組み込まれています。代わりに Firestore に保存するには、独自の Rack::Session オブジェクトを定義する必要があります。

  • sessions ディレクトリに、次の内容の firestore_session.rb というファイルを作成します。

    require "google/cloud/firestore"
    require "rack/session/abstract/id"
    
    module Rack
      module Session
        class FirestoreSession < Abstract::Persisted
          def initialize app, options = {}
            super
    
            @firestore = Google::Cloud::Firestore.new
            @col = @firestore.col "sessions"
          end
    
          def find_session _req, session_id
            return [generate_sid, {}] if session_id.nil?
    
            doc = @col.doc session_id
            fields = doc.get.fields || {}
            [session_id, stringify_keys(fields)]
          end
    
          def write_session _req, session_id, new_session, _opts
            doc = @col.doc session_id
            doc.set new_session, merge: true
            session_id
          end
    
          def delete_session _req, session_id, _opts
            doc = @col.doc session_id
            doc.delete
            generate_sid
          end
    
          def stringify_keys hash
            new_hash = {}
            hash.each do |k, v|
              new_hash[k.to_s] =
                if v.is_a? Hash
                  stringify_keys v
                else
                  v
                end
            end
            new_hash
          end
        end
      end
    end

セッションの削除

記載のとおり、このアプリは古いセッションや期限切れのセッションを削除しません。Cloud de Confiance コンソールセッション データを削除するか、自動削除戦略を実装できます。

ローカルでの実行

  1. HTTP サーバーを始動します。

    bundle exec ruby app.rb
    
  2. ウェブブラウザでアプリを表示します。

    「Hello World」、「Hallo Welt」、「Hola mundo」、「Salut le Monde」、「Ciao Mondo」の 5 つの挨拶のいずれかが表示されます。別のブラウザまたはシークレット モードでページを開くと、別の言語で表示されます。セッション データは Cloud de Confiance コンソールで表示して編集できます。

  3. HTTP サーバーを停止するには、ターミナル ウィンドウで Control+C を押します。

App Engine でのデプロイと実行

App Engine スタンダード環境を使用すると、高い負荷の下で大量のデータを使用して正常に動作するアプリをビルドしてデプロイできます。

このチュートリアルでは、App Engine スタンダード環境を使用してサーバーをデプロイします。

  1. ターミナル ウィンドウで app.yaml ファイルを作成し、このファイルに次の内容を貼り付けます。

    runtime: ruby25
    entrypoint: bundle exec ruby app.rb
  2. App Engine にアプリをデプロイします。

    gcloud app deploy
    
  3. 次の URL にあるライブアプリを表示します。ここで、PROJECT_ID は Cloud de Confiance プロジェクト ID です。

    https://PROJECT_ID.appspot.com

これで、App Engine インスタンスで実行しているウェブサーバーから挨拶が配信されます。

アプリのデバッグ

App Engine アプリに接続できない場合は、次の点を確認してください。

  1. gcloud デプロイ コマンドが正常に終了して、エラーを出力しなかったことを確認します。エラー(message=Build failed など)が発生した場合は、それらを修正してから、もう一度、App Engine アプリのデプロイを試みます。
  2. Cloud de Confiance コンソールで、[ログ エクスプローラ] ページに移動します。

    [ログ エクスプローラ] ページに移動

    1. [最近選択したリソース] プルダウン リストで、[App Engine アプリケーション] をクリックしてから、[All module_id] をクリックします。アプリにアクセスした以降のリクエストのリストが表示されます。リクエストのリストが表示されない場合は、プルダウン リストで [All module_id ] が選択されていることを確認します。エラー メッセージが Cloud de Confiance コンソールに出力された場合は、アプリのコードがウェブアプリの作成に関するセクション内のコードと一致することを確認します。

    2. Firestore API が有効になっていることを確認します。

クリーンアップ

プロジェクトを削除する

  1. Cloud de Confiance コンソールで [リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

App Engine インスタンスの削除

  1. Cloud de Confiance コンソールで、App Engine の [バージョン] ページに移動します。

    [バージョン] に移動

  2. デフォルト以外で削除するアプリのバージョンのチェックボックスをオンにします。
  3. アプリのバージョンを削除するには、[削除] をクリックします。

次のステップ