Skip to content

Commit

Permalink
Star モデルを作成し、インポータも作成した (#29)
Browse files Browse the repository at this point in the history
* Add Star model and its migration & test

* Add spreadsheet configuration file

* Add SpreadsheetService API with managers

* Add spreadsheet credentials file path

* Add data import service for Star model

* Add star table with name, name_en, seating_order

* Refactor ImportService::Base class and IndexesThe commit refactors the ImportService::Base class and removes name_en index from the schema

* Update database.yml for development and test environments

* Add default value for SPREADSHEET_CREDENTIALS_FILEPATH
  • Loading branch information
nikukyugamer authored Jun 12, 2023
1 parent 77b55fb commit bc154d8
Show file tree
Hide file tree
Showing 20 changed files with 271 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .env.tpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# $ op inject -i .env.tpl -o .env
RAILS_MASTER_KEY=op://Personal/b7nzrxcuyvy37cafgu3octmoyq/add more/suikoden_vault
SPREADSHEET_CREDENTIALS_FILEPATH=config/spreadsheet/creds.json

PG_DEVELOPMENT_HOST=op://Personal/7osscqrsds2jmobocq2twd5pjq/yl3pacrx662v4yd7vxmhypw52i
PG_DEVELOPMENT_PORT=op://Personal/7osscqrsds2jmobocq2twd5pjq/port
Expand All @@ -18,3 +19,7 @@ PG_PRODUCTION_PASS=op://Personal/irwrv7xiofnmimbcdz7d3wclqi/password
PG_SSLCERT_PATH=
PG_SSLKEY_PATH=
PG_SSLROOT_PATH=

# スプレッドシートID
SPREADSHEET_ID_BASIC_ATTRIBUTES=op://Personal/nouerwwfqtd67aeagpyrug3kiq/fudicawf773buqbjztwh3xzmeu/basic_attributes
SPREADSHEET_ID_PRODUCTS=op://Personal/nouerwwfqtd67aeagpyrug3kiq/fudicawf773buqbjztwh3xzmeu/products
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ config/postgresql/client.crt
config/postgresql/client.key
config/postgresql/root.crt

config/spreadsheet/creds.json

# デフォルト項目
/.bundle
vendor/
Expand Down
2 changes: 2 additions & 0 deletions app/models/star.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Star < ApplicationRecord
end
19 changes: 19 additions & 0 deletions app/service/fetch_data_table_service/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module FetchDataTableService
class Base
def initialize(*args)
# TODO: 書く
end

def headers
raise NotImplementedError
end

def rows
raise NotImplementedError
end

def header_to_rows
raise NotImplementedError
end
end
end
49 changes: 49 additions & 0 deletions app/service/fetch_data_table_service/from_spreadsheet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module FetchDataTableService
class FromSpreadsheet < Base
def initialize(spreadsheet_id, worksheet_name)
super

sheets_api = SpreadsheetService::SheetsApi.create
spreadsheet_manager = spreadsheet_manager(sheets_api, spreadsheet_id)
spreadsheet = spreadsheet_manager.spreadsheet

@worksheet_manager = worksheet_manager(sheets_api, spreadsheet, worksheet_name)
end

def headers
@worksheet_manager.headers
end

def rows
@worksheet_manager.rows
end

def header_to_rows
{}.tap do |hash|
headers.each do |header|
rows.each do |row|
hash[header.to_sym] ||= []
hash[header.to_sym] << row[headers.index(header)]
end
end
end
end

private

def spreadsheet_manager(sheets_api, spreadsheet_id)
SpreadsheetService::SpreadsheetManager.new(
sheets_api,
spreadsheet_id
)
end

def worksheet_manager(sheets_api, spreadsheet, worksheet_name)
SpreadsheetService::WorksheetManager.new(
sheets_api,
spreadsheet,
worksheet_name
)
end
end
end
21 changes: 21 additions & 0 deletions app/service/import_service/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module ImportService
class Base
class << self
def execute
raise NotImplementedError
end

def columns
raise NotImplementedError
end

def values
raise NotImplementedError
end

def data_table
raise NotImplementedError
end
end
end
end
28 changes: 28 additions & 0 deletions app/service/import_service/star.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module ImportService
class Star < Base
class << self
def execute
ActiveRecord::Base.transaction do
::Star.import(columns, values, validate: true)
end
end

def columns
data_table.headers.map(&:to_sym)
end

def values
data_table.rows
end

def data_table
spreadsheet_title = 'basic_attributes'

spreadsheet_id = SpreadsheetService::SheetId.retrieve(spreadsheet_title)
worksheet_name = 'stars'

FetchDataTableService::FromSpreadsheet.new(spreadsheet_id, worksheet_name)
end
end
end
end
20 changes: 0 additions & 20 deletions app/service/import_service/title.rb

This file was deleted.

37 changes: 0 additions & 37 deletions app/service/spreadsheet_service.rb

This file was deleted.

16 changes: 16 additions & 0 deletions app/service/spreadsheet_service/sheet_id.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module SpreadsheetService
class SheetId
class << self
def retrieve(spreadsheet_title)
title_to_id[spreadsheet_title]
end

def title_to_id
{
'basic_attributes' => ENV.fetch('SPREADSHEET_ID_BASIC_ATTRIBUTES'),
'products' => ENV.fetch('SPREADSHEET_ID_PRODUCTS')
}
end
end
end
end
28 changes: 28 additions & 0 deletions app/service/spreadsheet_service/sheets_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'google/apis/sheets_v4'

module SpreadsheetService
class SheetsApi
CREDS_JSON_FILEPATH = ENV.fetch('SPREADSHEET_CREDENTIALS_FILEPATH', nil)

class << self
def create
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open(CREDS_JSON_FILEPATH),

# drive と drive.file も必要になることには注意する
scope: %w[
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/spreadsheets
]
)
authorizer.fetch_access_token!

api = Google::Apis::SheetsV4::SheetsService.new
api.authorization = authorizer

api
end
end
end
end
10 changes: 10 additions & 0 deletions app/service/spreadsheet_service/spreadsheet_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module SpreadsheetService
class SpreadsheetManager
attr_reader :spreadsheet, :worksheet_names

def initialize(sheets_api, spreadsheet_id)
@spreadsheet = sheets_api.get_spreadsheet(spreadsheet_id)
@worksheet_names = @spreadsheet.sheets.map(&:properties).map(&:title)
end
end
end
36 changes: 36 additions & 0 deletions app/service/spreadsheet_service/worksheet_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module SpreadsheetService
class WorksheetManager
attr_reader :worksheet, :headers, :rows

def initialize(sheets_api, spreadsheet, worksheet_name, range: 'A1:Z')
@sheets_api = sheets_api
@spreadsheet = spreadsheet

@worksheet = @spreadsheet.sheets.find do |sheet|
sheet.properties.title == worksheet_name
end

@all_cells = all_cells(@worksheet, range:)
@headers = @all_cells.first
@rows = @all_cells.drop(1)

raise 'Some cells are invalid.' unless valid_all_cells?
end

def all_cells(worksheet, range: 'A1:Z')
# 戻り値からは nil が取り除かれる
@sheets_api.get_spreadsheet_values(
@spreadsheet.spreadsheet_id,
"#{worksheet.properties.title}!#{range}"
).values
end

def valid_all_cells?
return false if @headers.blank? || @rows.blank?

@rows.each { |row| return false if row.size != @headers.size }

true
end
end
end
30 changes: 15 additions & 15 deletions config/database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@ default: &default
development:
<<: *default
database: suikoden_vault_development
host: <%= ENV.fetch('PG_DEVELOPMENT_HOST') || 'localhost' %>
port: <%= ENV.fetch('PG_DEVELOPMENT_PORT') || 5432 %>
username: <%= ENV.fetch('PG_DEVELOPMENT_USER') || 'root' %>
password: <%= ENV.fetch('PG_DEVELOPMENT_PASS') || 'postgres' %>
host: <%= ENV['PG_DEVELOPMENT_HOST'] || 'localhost' %>
port: <%= ENV['PG_DEVELOPMENT_PORT'] || 5432 %>
username: <%= ENV['PG_DEVELOPMENT_USER'] || 'root' %>
password: <%= ENV['PG_DEVELOPMENT_PASS'] || 'postgres' %>

test:
<<: *default
database: suikoden_vault_test
host: <%= ENV.fetch('PG_TEST_HOST') || 'localhost' %>
port: <%= ENV.fetch('PG_TEST_PORT') || 5432 %>
username: <%= ENV.fetch('PG_TEST_USER') || 'root' %>
password: <%= ENV.fetch('PG_TEST_PASS') || 'postgres' %>
host: <%= ENV['PG_TEST_HOST'] || 'localhost' %>
port: <%= ENV['PG_TEST_PORT'] || 5432 %>
username: <%= ENV['PG_TEST_USER'] || 'root' %>
password: <%= ENV['PG_TEST_PASS'] || 'postgres' %>

production:
<<: *default
database: suikoden_vault_production
host: <%= ENV.fetch('PG_PRODUCTION_HOST') || 'localhost' %>
port: <%= ENV.fetch('PG_PRODUCTION_PORT') || 5432 %>
username: <%= ENV.fetch('PG_PRODUCTION_USER') %>
password: <%= ENV.fetch('PG_PRODUCTION_PASS') %>
host: <%= ENV['PG_PRODUCTION_HOST'] || 'localhost' %>
port: <%= ENV['PG_PRODUCTION_PORT'] || 5432 %>
username: <%= ENV['PG_PRODUCTION_USER'] %>
password: <%= ENV['PG_PRODUCTION_PASS'] %>
sslmode: verify-ca
sslcert: <%= ENV.fetch('PG_SSLCERT_PATH') || 'config/postgresql/client.crt' %>
sslkey: <%= ENV.fetch('PG_SSLKEY_PATH') || 'config/postgresql/client.key' %>
sslrootcert: <%= ENV.fetch('PG_SSLROOT_PATH') || 'config/postgresql/root.crt' %>
sslcert: <%= ENV['PG_SSLCERT_PATH'] || 'config/postgresql/client.crt' %>
sslkey: <%= ENV['PG_SSLKEY_PATH'] || 'config/postgresql/client.key' %>
sslrootcert: <%= ENV['PG_SSLROOT_PATH'] || 'config/postgresql/root.crt' %>
Empty file added config/spreadsheet/.keep
Empty file.
14 changes: 14 additions & 0 deletions db/migrate/20230612121238_create_stars.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateStars < ActiveRecord::Migration[7.0]
def change
create_table :stars do |t|
t.string :name, null: false, comment: '宿星の名前(日本語)'
t.string :name_en, null: false, comment: '宿星の名前(英語)'
t.integer :seating_order, null: false, comment: '席次'

t.timestamps
end

add_index :stars, :name, unique: true
add_index :stars, :seating_order, unique: true
end
end
12 changes: 11 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion lib/tasks/db/reconstruction.rake
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ namespace :db do
task execute: :environment do
Rake::Task['db:migrate:reset'].invoke

# 時間がかかるようになったらこのあたりにスキップするロジックを組み込む
puts "[#{Time.zone.now}] ImportService::Star.execute の実行を開始します。"
ImportService::Star.execute
puts "[#{Time.zone.now}] ImportService::Star.execute の実行が終了しました。"

# 時間がかかるようになったらスキップするロジックを組み込む
# Rake::Task['importer:foo:bar'].invoke
# Rake::Task['importer:hoge:fuga'].invoke
# Rake::Task['importer:piyo:puyo'].invoke
Expand Down
5 changes: 5 additions & 0 deletions spec/factories/stars.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FactoryBot.define do
factory :star do

end
end
Loading

0 comments on commit bc154d8

Please sign in to comment.