たくみん成長日記

開発したアプリやプログラミングの備忘録を不定期に上げていきます。

Sinatraのdatabase.ymlでdotenvを使いたい

こんちか!! たくみんです。最近はSinatraを使って、ちょっとしたWebアプリを作っています。その際にハマったポイントがあるので、備忘録として記事を書いています。

開発中のアプリケーションの構成は、以下のような感じです。

  • rbenv : 1.1.1-39-g59785f6
  • ruby : 2.6.0
  • sinarra : 2.0.5
  • mysql : Ver 8.0.13 for osx10.14 on x86_64 (Homebrew)
./
├── app.rb
├── config.ru
├── database.yml
├── Gemfile
└── Gemfile.lock

ハマったポイント

今回開発中のアプリケーションでは、databaseに接続するための情報を、database.ymlに記述することにしました。

qiita.com

しかしながら、ユーザネームやパスワードなどの情報を、GitHubのpublicリポジトリにpushするのは、あまりよくありません。 そこで、.envgem dotenvによる管理を行うことにしました。

Railsのdatabase.ymlには、erb記法が利用できるという記事を発見したので、Sinatraでも行けるでしょと思い、やってみることにしました。

shuzo-kino.hateblo.jp

そのときのdatabase.ymlとSinarraのapp.rbは以下のような感じです。

adapter: mysql2
encoding: utf8
reconnect: false
database: sqlapps
pool: 5
username: <%= ENV["MYSQL_USERNAME"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
host: localhost
require 'sinatra'
require 'sinatra/reloader'
require 'mysql2'
require 'dotenv'
require 'yaml'

set :bind, '0.0.0.0'
Dotenv.load
sql_client = Mysql2::Client.new(YAML.load_file('./database.yml'))

get '/' do
  # 省略
end

Sinatraを起動してみると、以下のように、erb記法がうまく解釈されておらず、接続ができていないことがわかります。

Access denied for user '<%= ENV["MYSQL_USERNAME"] %>'@'localhost' (using password: YES) (Mysql2::Error::ConnectionError)

解決方法

解決方法が以下の記事に乗っていました。

www.ohmg.tokyo

この記事によると、以下の手順を踏むことで、解決できるようです。

  1. File.readでdatabase.ymlを読み込む
  2. ERB.new()の引数に、1.を与える
  3. 2.の結果をresult methodで取り出し、yamlとして読み込ませる
  4. 3.の結果をmysql2の引数として与える

コードにすると以下のような感じです。

Mysql2::Client.new(YAML.load(ERB.new(File.read("./database.yml")).result))

修正結果

解決方法を踏まえて、Sinatraのapp.rbを以下のように修正しました。

require 'sinatra/base'
require 'sinatra/reloader'
require 'mysql2'
require 'dotenv'
require 'yaml'
require 'erb'

class SQLApplication < Sinatra::Base

Dotenv.load
yaml_file = File.read("./database.yml")
sql_client = Mysql2::Client.new(YAML.load(ERB.new(yaml_file).result))

  get '/' do
    query = "select * from test1"
    output = ""
    result = sql_client.query(query)
    result.each do |a|
      output =  a["text"]
    end
    return output
  end
end

疎通確認として、適当なテーブルを作成し、表示させてみます。 テーブルは以下のような感じです。

test1
+---------------+-------------+
| id(integer)   | text (text) |
+---------------+-------------+
|    1          | test        |
+---------------+-------------+

表示結果が下の画像です。 f:id:takuminv:20190115020854p:plain

成功です。うまくQueryの結果を表示していることがわかります。

終わりに

Railsだと、コマンド叩いてけばdatabase.ymlが勝手に作られ、 dotenv-railsのおかげで、勝手にerbを解釈してくれるので、楽なのですが、 Sinatraだと全部自分でやらないといけないので、勉強になりました。

やっぱりRailsってすごい…