Ruby on RailsでGoogle Calendar API Quick Start

# はじめに
Ruby on RailsでGoogle Calendar APIを叩くの激ムズだったんですけどようやく完全に理解したので以下備忘録。
https://developers.google.com/calendar/quickstart/ruby
ググって出てくるページは古いし公式のquickstartはRubyなので、それらをRailsで実現するのに大苦労した。

# Google API Consoleでの下準備
[Google API Console](https://console.cloud.google.com/apis/)でAPIを有効化しよう。
![スクリーンショット 2020-12-16 12.10.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262342/31a60b77-be39-66b4-00b6-afcf34dc5aa6.png)
上画像の上にある「APIとサービスの有効化」からCalendarとGmailを有効化する。

![スクリーンショット 2020-12-16 12.12.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262342/8ac0c0b3-a2bf-2755-a22c-7fe9e506df65.png)
次に上画像の上の「認証情報を作成」から「OAuthクライアントID」の作成を選択する。
アプリケーションの種類は「ウェブアプリケーション」
名前は各自好きなものを追加し、作成完了。

ここはググればいっぱい出てくるはずなので分からなかったら調べてください。

###注意点

- Google Calendar APIを使いたい場合は、Calendarと**Gmail**も有効化しないといけないらしい。

- APIキーはGoogle Map APIとか認証情報が必要ないものを使うときに使う。
Google Calendar APIはユーザーに認証してもらって代わりにアプリがデータを取ってくる流れになるのでOAuthクライアントが必要。

# localhostからlvh.meへ
ローカルで開発している場合はHOSTが "http://localhost:3000" とかだと思うが、これだとgoogle OAuth的に何かよくないっぽい。(エラーと格闘してるときにそんな感じの記事見ただけでここはよく分からんです🙏 localhostでもいけるかもしれん)

```ruby:config/environments/development.rb
Rails.application.configure do
  # 以下を追加
  config.hosts<<"lvh.me"
```

これで "http://lvh.me:3000" が使えるはず。

# Calendarを扱うcontrollerの作成
さてrailsでゴリゴリやっていこう。まずカレンダーの認証等を扱うCalendarControllerを作成します。名前とかはなんでもいいけど。

```terminal:terminal
rails generate controller Calendar index callback
```

とでもターミナルで実行してcontroller作成done

```ruby:app/controller/CalendarController.rb
require "google/apis/calendar_v3"
require "googleauth"
require "googleauth/stores/file_token_store"
require "date"
require "fileutils"

class CalendarController < ApplicationController

  REDIRECT_URI = "http://lvh.me:3000/oauth2callback".freeze
  APPLICATION_NAME = "下準備の所で設定したアプリの名前".freeze
  CLIENT_SECRET_PATH = "client_secret.json".freeze
  # The file token.yaml stores the user's access and refresh tokens, and is
  # created automatically when the authorization flow completes for the first
  # time.
  TOKEN_PATH = "credentials.yaml".freeze
  SCOPE = Google::Apis::CalendarV3::AUTH_CALENDAR
  MY_CALENDAR_ID = 'primary'

  def index
  end

  def authorize
    client_id = Google::Auth::ClientId.from_file CLIENT_SECRET_PATH
    logger.debug(client_id.id)
    token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
    authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
    user_id = "hoge@gmail.com(テスト用なので自分のジーメール)"
    credentials = authorizer.get_credentials user_id
    if credentials.nil?
      code = session[:code]
      url = authorizer.get_authorization_url(base_url: REDIRECT_URI)
      logger.debug(url)
      credentials = authorizer.get_and_store_credentials_from_code(
        user_id: user_id, code: code, base_url: REDIRECT_URI
      )
    end
    credentials
  end


  def callback
    session[:code] = params[:code]
    logger.debug(session[:code])
    calendar = Google::Apis::CalendarV3::CalendarService.new
    calendar.client_options.application_name = APPLICATION_NAME
    calendar.authorization = authorize
    fetchEvents(calendar)
    redirect_to action: :index
  end

  def fetchEvents(service)
    # Fetch the next 10 events for the user
    calendar_id = MY_CALENDAR_ID
    response = service.list_events(calendar_id,
                                   max_results:   10,
                                   single_events: true,
                                   order_by:      "startTime",
                                   time_min:      DateTime.now.rfc3339)
    puts "Upcoming events:"
    puts "No upcoming events found" if response.items.empty?
    response.items.each do |event|
      start = event.start.date || event.start.date_time
      puts "- #{event.summary} (#{start})"
    end
  end
end
```

基本的には公式のquickstartを関数分けて移植したくらい。
公式のOOB_URIって意味わからんけど要はredirectURIのことやと理解したので、勝手に変数名変えて"http://lvh.me:3000/oauth2callback" にした。
細かい説明は割愛。


###注意点
REDIRECT_URIは"http://lvh.me:3000/oauth2callback" にする。変更しない。
後に生成されるauthorizationのredirect_urlがこれなので、変更するとREDIRECT_URI_MISMATCHって出る(はず)

# redirect_urlを設定
[Google API Console](https://console.cloud.google.com/apis/)で、先ほど作ったOAuthクライアントIDを選択し、
承認済みのJavaScript生成元に"http://lvh.me:3000"
承認済みのリダイレクト URIに"http://lvh.me:3000/oauth2callback"
と記載。

できたらJSONをダウンロードしアプリのルートディレクトリに"client_secret.json"とリネームし保存しておく。

# ルーティングの設定

```ruby:config/routes.rb
  get "calendar/index", to:"calendar#index"
  get "oauth2callback", to:"calendar#callback"
```
の二行を追加。

#準備オッケー！  流れの確認
さて、ここまでできたらrails sして

```
https://accounts.google.com/o/oauth2/auth?response_type=code&
client_id=<client_secret.jsonに書いてるclient_id>&redirect_uri=http://lvh.me:3000/oauth2callback&
scope=https://www.googleapis.com/auth/calendar&
access_type=offline&
approval_prompt=force
```
のclient_idのとこを自分のものに変えてアクセスする。
するとgoogleの権限認証画面に遷移する。
許可するとまず "http://lvh.me:3000/oauth2callback" に、codeパラメータを持ってリダイレクトされる。
すなわちCalendarControllerのcallbackメソッドが実行される。

callbackメソッド内でauthorize関数を呼び出しているので、そこでcodeがtokenに変換され、credentials.yamlに保存される。

この時点でターミナルにurl = authorizer.get_authorization_url(base_url: REDIRECT_URI)で作成したurlが表示されているはず。
REDIRECT_URI_MISMATCHとかいうエラーが出る場合、設定しているリダイレクトURLが表示されてるurl内のredirect_urlと異なっている可能性がある。
(ここがわからなくてずっと詰まってた、、)

認証が上手く終わっていればfetchEventsが実行され、ターミナルにあなたのカレンダーの予定が表示されています！！！！

***Congratulations!***

今はローカルにcredentials等を保存しているので、Redisとかで管理できるといいっぽいですね！

# おわりに
devise使ってOAuth認証でユーザー管理もしてるので、そっちとコードがごっちゃになっていたのが詰まっていた所以かもしれない。
抜けている所、これ不要だよ等々あったら教えてください！
lgtmもください！