14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-03-16

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 の基礎

14
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?