LoginSignup
48
42

More than 5 years have passed since last update.

RailsでGoogle Spreadsheetsをいい感じに使える+ActiveRecordとデータ同期とか

Last updated at Posted at 2013-12-30

(追記) OAuth2認証に対応しました。

こういうの作ってます。

こういうスプレッドシートを用意しておく。

タイトルは何でもいい。idは必須。シートの名前は標準では[モデル名]_rows

screenshot

spreadsheet = GoogleSpreadsheets::Enhanced::Spreadsheet.find('0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c')
# GET /feeds/spreadsheets/private/full/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c HTTP/1.1
# Authorization: GoogleLogin auth=xxxx
# Accept: application/atom+xml
# Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
# User-Agent: Ruby
# Connection: close
# Host: spreadsheets.google.com
# 
# HTTP/1.1 200 OK
# …
#
# => #<GoogleSpreadsheets::Enhanced::Spreadsheet:0x007f95d2283880>

worksheet = spreadsheet.worksheets.find_by(title: 'user_rows')
# GET /feeds/worksheets/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c/private/full HTTP/1.1
# …
#
# => #<GoogleSpreadsheets::Enhanced::Worksheet:0x007f95d2338780>

rows = worksheet.rows
# GET /feeds/list/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c/od1/private/full HTTP/1.1
# …
#
# => #<GoogleSpreadsheets::Enhanced::Collection:0x007f95d2492158>

こんな感じで、spreadsheetからたどっていける。

ActiveRecordとの同期

app/models/user.rb
class User < ActiveRecord::Base
  include GoogleSpreadsheets::Enhanced::Syncing
  sync_with :user_rows, spreadsheet_id: '0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c'
  after_commit :sync_user_row
end

sync_with :user_rowsによって、以下のメソッドが定義される。(has_many :user_rowsみたいなイメージ)

  • user_rows
  • sync_with_user_rows
  • sync_user_row

User.user_rows

このメソッドは自動でspreadsheetsからリンクをたどって、ActiveResourceオブジェクト(のコレクション)を返す。

user_rows = User.user_rows

# GET /feeds/spreadsheets/private/full/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c HTTP/1.1
# …
# GET /feeds/worksheets/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c/private/full HTTP/1.1
# …
# GET /feeds/list/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c/od1/private/full HTTP/1.1
# …
# => #<GoogleSpreadsheets::Enhanced::Collection:0x007f87cc7bccc0 @elements=[#<GoogleSpreadsheets::Enhanced::Row:0x007f87cc7bcb30 @attributes={…}, …

ActiveResourceオブジェクトなのでfindとかsaveとか、ActiveRecordっぽい扱いが可能。

user_row = user_rows.find(id)
user_row.name = 'foo'
user_row.save
# PUT /feeds/list/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c/od1/private/full HTTP/1.1
# …

User.sync_with_user_rows

Spreadsheetのデータはsync_with_user_rowsメソッドでActiveRecord側に一括同期可能。

User.sync_with_user_rows

# GET /feeds/list/0AtkgjSZyl3NLdEE1S0lvbEdZLU00ZndhMXFzLW44SlE/od1/private/full HTTP/1.1
#
# begin transaction
# UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = 1  [["name", “foo"],  ["updated_at", Sun, 29 Dec 2013 23:17:30 JST +09:00]]
# UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = 13  [["name", "bar"],  ["updated_at", Sun, 29 Dec 2013 23:17:31 JST +09:00]]
# commit transaction

User#sync_user_row

レコード単位でシート側へ同期するメソッド。after_commit :sync_user_rowを書いておけば、user_rowではなく普通のuserオブジェクトをsaveしても同期されるようになる。

user = User.find(id)
user.name = 'bar'
user.save

# UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = 13  [["name", "bar"],  ["updated_at", Sun, 29 Dec 2013 23:17:30 JST +09:00]]
#
# PUT /feeds/list/0AtkgjSZyl3NLdERqdkdMZk01alFLWXZUZUtuNlcwN3c/od1/private/full HTTP/1.1
# …

設定

0.1.0からOAuth2に対応しました。
GoogleSpreadsheets::Base.auth_type = :bearerとして、GoogleSpreadsheets::Base.access_tokenに取得したaccess tokenをセットしてください。
GoogleSpreadsheets::Base.access_token do ... endの形でブロックも渡せます。必要なときに呼び出されるので、refreshなどに使えます。

Service Accounts の場合

ユーザ個別の権限が必要ない(2-legged)場合、Service Accountsという方式でaccess tokenを取得します。この場合に便利なクラスを用意しました。

Google Developers Consoleからプロジェクトを作成し、「認証情報」から「新しいクライアントIDを作成」、「サービスアカウント」を選んで作成してください。

Google_Developers_Console.jpg

クライアントIDが作成できたら、「新しいJSONキーを生成」でJSONファイルをダウンロードします。
その中の client_email と private_key を使用して以下のように設定してください。

config/initializers/google_spreadsheet.rb
GoogleSpreadsheets::Base.auth_type = :bearer
GoogleSpreadsheets::Base.access_token =
  GoogleSpreadsheets::Auth::ServiceAccountsAccessToken.new(
    client_email: '000000000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@developer.gserviceaccount.com',
    private_key_pem: "-----BEGIN PRIVATE KEY-----\n..."
  )

スプレッドシートが公開でない場合は、上のclient_emailに設定した...@developer.gserviceaccount.comのユーザに共有設定で権限を与えることでアクセスできるようになります。

参考:http://d.hatena.ne.jp/sugyan/20130112/1357996092

他の方式に対応したクラスも作るかも。

以下のClientLogin認証は古い記述で非推奨です

Googleユーザ名とパスワードの設定が必要。

config/initializers/google_spreadsheet.rb
GoogleSpreadsheets::Base.user = 'google_acount@gmail.com'
GoogleSpreadsheets::Base.password = 'password'

※2段階認証を有効にしている場合は、アプリケーション固有のパスワードを生成してそれを使ってください。

カスタムクラスを使う場合

sync_with :user_rowsの場合、名前に対応するUserRowクラスがあればそれが使われる。(has_manyみたいなイメージ)

スプレッドシート上の列名が属性名と異なる場合、カスタムクラスを作成してattr_aliasesで指定できる。

app/models/user_row.rb
class UserRow < GoogleSpreadsheets::Enhanced::Row
  attr_aliases(
    name:    '名前',
    address: '住所'
  )
  # user.name で 「名前」列
  # user.address で 「住所」列にアクセスできる
end

スプレッドシートの列名は、アルファベット大文字や記号類が使用できない(すべて小文字になり、記号類は削除される)ので注意。

48
42
0

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
48
42