事前準備

Google Cloud Platform

  • Google Cloud Platform Console
    1. 新規プロジェクト (datastore-test) を作成
    2. Cloud Datastore API を有効化
    3. プロジェクトにアクセスするためのサービスアカウントを作成

Google Cloud SDK

wget -O - 'https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-137.0.1-darwin-x86_64.tar.gz' | tar zxf -
./google-cloud-sdk/install.sh
gcloud components update
gcloud init
.
.
.
Pick cloud project to use:
 [1] hoge
 [2] datastore-test
 [3] fuga
Please enter numeric choice or text value (must exactly match list
item):  2
.
.
.
gcloud config list
Your active configuration is: [default]

[core]
account = [email protected]
disable_usage_reporting = True
project = datastore-test

Rails

Rails からプロジェクト名 (datastore-test) を参照できるようにしておく.また,今回はローカルエミュレータを用いるため必要ないが,実際の Datastore API を利用するときのために, GCP サービスアカウントの鍵ファイル (json) へのパスを参照できるようにしておく.

ruby -v
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16]
mkdir datastore && cd $_
# Gemfile

source 'https://rubygems.org'

gem 'rails', '5.0.2'
bundle install --path vendor/bundle --jobs=4
bundle exec rails new .
# Gemfile

+gem 'google-cloud'
bundle install

今回は settingslogic を利用してプロジェクト名と鍵のパスを設定する.

# Gemfile

+gem 'settingslogic'
bundle install
# config/gcp.yml

default: &default
  datastore:
    dataset_id: datastore-test
    key: /path/to/your/key.json

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default
# config/initializers/gcp_settings.rb

class GcpSettings < Settingslogic
  source "#{Rails.root}/config/gcp.yml"
  namespace Rails.env
end
bundle exec rails c
irb> GcpSettings.datastore.dataset_id
=> "datastore-test"
irb> GcpSettings.datastore.key
=> "/path/to/your/key.json"

Datastore エミュレータ

gcloud beta emulators datastore start

エミュレータ起動後,エミュレータへの接続情報を環境変数に設定する.

$(gcloud beta emulators datastore env-init)

チュートリアル

資料

用語

RDBDatastore
テーブル種類
エンティティ
フィールドプロパティ
主キーキー

モデル

Google::Cloud::Datastore には ORM が用意されていないため自前でコードを書く必要がある.サンプルとして下表に示す Movie モデルを作成する.

種類キープロパティプロパティプロパティ
Movieidyeartitleinfo
# app/models/movie.rb

require 'google/cloud/datastore'

class Movie
  attr_accessor :id, :year, :title, :info

  def self.dataset
    @dataset ||= Google::Cloud::Datastore.new(
      project: GcpSettings.datastore.dataset_id
    )
  end

  def self.from_entity entity
    movie = Movie.new
    movie.id = entity.key.id
    entity.properties.to_hash.each do |name, value|
      movie.send "#{name}=", value if movie.respond_to? "#{name}="
    end
    movie
  end

  def self.find id
    query    = Google::Cloud::Datastore::Key.new "Movies", id.to_i
    entities = dataset.lookup query

    from_entity entities.first if entities.any?
  end

  include ActiveModel::Model

  def save
    if valid?
      entity = to_entity
      Movie.dataset.save entity
      self.id = entity.key.id
      true
    else
      false
    end
  end

  def to_entity
    entity          = Google::Cloud::Datastore::Entity.new
    entity.key      = Google::Cloud::Datastore::Key.new "Movies", id
    entity["year"]  = year
    entity["title"] = title
    entity["info"]  = info if info
    entity
  end

  def update attributes
    attributes.each do |name, value|
      send "#{name}=", value if respond_to? "#{name}="
    end
    save
  end

  def destroy
    Movie.dataset.delete Google::Cloud::Datastore::Key.new "Movies", id
  end

  def persisted?
    id.present?
  end
end

以下, Rails コンソールから Movie モデルを利用する.なお, Datastore には RDB のテーブル定義のような概念はないようで,エンティティ作成時に指定した名称とキーで種類が作成される.

エンティティを作成する

irb> movie = Movie.new(id: 1, year: 2015, title: 'The Big New Movie', info: 'description')
=> #<Movie:0x007fc92ca307d0 @id=1, @year=2015, @title="The Big New Movie", @info="description">
irb> movie.save
=> true

エンティティを読み込む

irb> Movie.find(1)
=> #<Movie:0x007fc92e9d6f08 @id=1, @year=2015, @title="The Big New Movie", @info="description">

エンティティを更新する

irb> movie.update([['year', 2017], ['info', 'hoge']])
=> true
irb> Movie.find(1)
=> #<Movie:0x007fc929dab930 @id=1, @year=2017, @title="The Big New Movie", @info="hoge">

エンティティを削除する

irb> movie.id
=> 1
irb> movie.destroy
=> true
irb> Movie.find(1)
=> nil