ActiveJobでGoogleDriveのGoogleSpreadSheetへデータを書き込む

# Google_driveにデータを書き込む

Ruby on Railsでやります。

## Google_driveというGemをインストール

参考：[google_drive_ruby](https://github.com/gimite/google-drive-ruby)
Readmeにそれっぽい感じで書いてあるんだけど、あんまり役立たない。基本的なことだけ書いてあるのでそれを一所懸命ゴリゴリする想定でいてください。

``` Gemfile.
gem 'google_drive'
```

ちなみに試してた環境はRails 5.0.1です。いつもの、bundle installで。

## GoogleDriveApiのリフレッシュトークンの取得

参考：[Google API OAuth2.0のアクセストークン&amp;リフレッシュトークン取得手順 2017年2月版 - Qiita](http://qiita.com/iwaseasahi/items/2363dc1d246bc06baeae)

GoogleDriveAPIの取得方法は上記がすごく丁寧に載せてくださってます。
ただし、GoogleさんはガンガンUIを変えていくので、僕の試した2017年03月段階ですでに上記サイトのスクリーンショットとは異なっていました。

とりあえずここを超えないとGoogleDriveに接続できない(つまりSpreadsheetに接続できない)。
**頑張れ**。

## GoogleDriveとの接続情報を保存しておく

config/settings.ymlに入れておくのがいい。
("config"というgem使ってください)

```config/settings.yml
google_drive:
  client_id: 888*******21-9**************pphq9kdo6.apps.googleusercontent.com
  client_secret: d5e*******************bCn
  code: 4/2Icegy****************ytq0boS8#
  refresh_token: 1/MxzVY-0G7Xu*******************aoHLY
  access_token: ya29.GlsCBNH**************Gc_WcIqXufnqBo2ZSLD*******GFJA5UpCpp1l
```

上記は一例(＊は伏せ字にしてるだけ。本当はアルファベットや記号)。
先程頑張って手に入れたrefresh_tokenなどを書き込む。
なお、必要になるのは**client_id**、**client_secret**、**refresh_token**だけ。
codeはそのtokenを取るように必要で、access_tokenは変わってしまうのでrefresh_tokenしか使わない（ここではなんとなく取っといただけ）。

## ActiveJobの作成

さてここからRailsのActiveJobを作っていきます。

### GoogleDriveとの接続

``` app/jobs/ws_save_job.rb
  private
    def google_drive
      credentials = Google::Auth::UserRefreshCredentials.new(
        client_id:     Settings.google_drive.client_id,
        client_secret: Settings.google_drive.client_secret,
        scope:         %w(https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds/),
        redirect_uri:  'http://example.com/redirect'
      )
      credentials.refresh_token = Settings.google_drive.refresh_token
      credentials.fetch_access_token!
      GoogleDrive::Session.from_credentials(credentials)
    end
```

こちらをコピペでお使いくださいｗ
さっきまでの手順でちゃんとrefresh_tokenやclient_idを作ってあれば、上記がコピペでいけます。
2014年ぐらいまでは、接続するためにgmailアドレスとそのパスワードを直書きするという仕様(！)でしたが、ちゃんとauthになっております。
redirect_uriはサンプルっぽく書いてありますが、GoogleDriveAPIのキーを発行するときに入力したはずのredirect_uriです。ぶっちゃけなんでもOKみたい。

### スプレッドシートのシート作成

プライベートメソッドでGoogleDriveとの接続は作ったのでスプレッドシートを作成します。

``` app/jobs/ws_save_job.rb
  def perform(ws_id = nil)
    google_drive
    ws = google_drive.spreadsheet_by_key(ws_id)
    ws_title = "シート名"
    ws = ws.worksheet_by_title(ws_title) || ws.add_worksheet(ws_title)
    insert_header(ws)
  end
```

#### def perform を作成
def performを作成します。performはActiveJobを普通にgenerateしたら出来上がります。(参考：[Active Job の基礎](https://railsguides.jp/active_job_basics.html))
なおここでは、ws_id(wsはワークシート)というGoogleスプレッドシートのファイル固有のIDをparamsで渡せるようにしておきます。

次に、privateメソッドで作っておいたgoogle_driveを呼び出して接続。

その次に、wsという変数にスプレッドシートのファイルを指定します。
ws_id にはGoogleスプレッドシートのURLに出てくる、「`https://docs.google.com/spreadsheets/d/1Mb4tYxcvbnmyu-RPwertyuiovhjk7Cdi6Mhwo2rb_m84/edit`」のd/の後ろの文字列を渡します(1Mb4tYxcvbnmyu-RPwertyuiovhjk7Cdi6Mhwo2rb_m84の部分)。これがws_idです。
※でたらめのURLですよ

シートの名前をつけたい場合に、 ws_title = "シート名" を変更します。
文字通りスプレッドシート内のシート名を変えることができます。
paramsで渡したりもできるし、つけなくてもいいです。任意。

そして、
`ws = ws.worksheet_by_title(ws_title) || ws.add_worksheet(ws_title)`
は、かなり便利な一行。
シートがあったらそこにデータを追加するし、シートがなかったらシート作成ができる。
worksheet_by_title(ws_title)が既存。ws.add_worksheet(ws_title)が追加。
※add_worksheetとかいうメソッドを探すのに超時間かかったのは内緒だ。

privateメソッドに「insert_header」として、ヘッダー追加できるようにする。

``` app/jobs/ws_save_job.rb
  private
    def insert_header(ws)
      ws[1, 1] = "No"
      ws[1, 2] = "名前"
      ws[1, 3] = "URL"
      ws[1, 4] = "電話番号"
      ws[1, 5] = "住所"
      ws[1, 6] = "最終更新日"
    end
```
上記適当。
ws[1, 1]は、ワークシートの1行目、1列目(エクセルでいうと1行目のA列)。
ws[1, 4]は、ワークシートの1行目、4列目(エクセルでいうと1行目のD列)。

wsの後に配列っぽく表記することで行列を指定できるのは中々表現がわかりやすくて良い。

## さあ、配列ぶっこもう

``` app/jobs/ws_save_job.rb
    @array.each do |r|
      num_rows = ws.num_rows
      ws[num_rows + 1, 1] = num_rows
      ws[num_rows + 1, 2] = r.name
      ws[num_rows + 1, 3] = r.url
      ws[num_rows + 1, 4] = r.tel
      ws[num_rows + 1, 5] = r.address
      ws[num_rows + 1, 6] = "#{Time.current.strftime('%Y年%m月%d日 %T')}"
    end
    ws.save
```
上記で、eachぶん回すと1行ずつ6列に値がぼこぼこ入っていく形となります。

なお、
ws.num_rowsは、レコード数を取得。
ws.num_colsは、カラム数を取得。ここでは使ってないけど。
ws.saveはシートの保存。
ws.reloadはシートの最新を取得(要はF5です)。

## まとめ

ということで、ざっとまとめると、

``` app/jobs/ws_save_job.rb
class WsSaveJob < ApplicationJob
  queue_as :default

  def perform(ws_id = nil)
    google_drive
    ws = google_drive.spreadsheet_by_key(ws_id)
    ws_title = "シート名"
    ws = ws.worksheet_by_title(ws_title) || ws.add_worksheet(ws_title)
    insert_header(ws)

    @array.each do |r|
      num_rows = ws.num_rows
      ws[num_rows + 1, 1] = num_rows
      ws[num_rows + 1, 2] = r.name
      ws[num_rows + 1, 3] = r.url
      ws[num_rows + 1, 4] = r.tel
      ws[num_rows + 1, 5] = r.address
      ws[num_rows + 1, 6] = "#{Time.current.strftime('%Y年%m月%d日 %T')}"
    end
    ws.save
  end

  private
    def google_drive
      credentials = Google::Auth::UserRefreshCredentials.new(
        client_id:     Settings.google_drive.client_id,
        client_secret: Settings.google_drive.client_secret,
        scope:         %w(https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds/),
        redirect_uri:  'http://example.com/redirect'
      )
      credentials.refresh_token = Settings.google_drive.refresh_token
      credentials.fetch_access_token!
      GoogleDrive::Session.from_credentials(credentials)
    end

    def insert_header(ws)
      ws[1, 1] = "No"
      ws[1, 2] = "名前"
      ws[1, 3] = "URL"
      ws[1, 4] = "電話番号"
      ws[1, 5] = "住所"
      ws[1, 6] = "最終更新日"
    end
```

以上。

今回参考にしたサイトは以下。ありがとうございました。
・[gimite/google-drive-ruby](https://github.com/gimite/google-drive-ruby)
・[Google API OAuth2.0のアクセストークン&リフレッシュトークン取得手順 2017年2月版](http://qiita.com/iwaseasahi/items/2363dc1d246bc06baeae)
・[Google DriveのスプレッドシートにRubyでアクセスする方法](http://qiita.com/yumiyon/items/d7c370b3b8582431a3de)
・[Active Job の基礎](https://railsguides.jp/active_job_basics.html)