Edited at

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

More than 1 year has passed since last update.


Google_driveにデータを書き込む

Ruby on Railsでやります。


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

参考:google_drive_ruby

Readmeにそれっぽい感じで書いてあるんだけど、あんまり役立たない。基本的なことだけ書いてあるのでそれを一所懸命ゴリゴリする想定でいてください。


Gemfile.

gem 'google_drive'


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


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

参考:Google API OAuth2.0のアクセストークン&リフレッシュトークン取得手順 2017年2月版 - Qiita

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_idclient_secretrefresh_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

こちらをコピペでお使いくださいw

さっきまでの手順でちゃんと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 の基礎)

なおここでは、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

Google API OAuth2.0のアクセストークン&リフレッシュトークン取得手順 2017年2月版

Google DriveのスプレッドシートにRubyでアクセスする方法

Active Job の基礎