TL;DR
RailsからMySQLに接続するときにcredentials.ymlから値を取得している場合には、ERBタグで囲うこと
例:
username: username
password: <%= Rails.application.credentials.dig(:db, :pw) %>
# 以下のようにしない
# password: Rails.application.credentials.dig(:db, :pw)
ハマるまで
Railsアプリの各鍵管理にはcredentials:editを使って暗号化するとのことだったので早速以下のようにDBのパスワードを設定
db:
password: myPassword
この状態で railsコンソールからputsして値が返ってくるので問題ないと判断。
bin/rails c
puts Rails.application.credentials.dig(:db, :pw)
# => myPasswordが返ってくる
MySQL内にデータベースを作るためbundle exec db:create を実行。
しかし、以下のようにアクセス拒否されてしまう
Mysql2::Error::ConnectionError: Access denied for user 'username'@'localhost' (using password: YES)
MySQL側で使用しているユーザーの権限が足りないのかなど色々調査。
原因
config/database.yml内に記述しているcredentialsから値を取得している部分に誤りがあった。
以下のようにERBタグで囲んだ状態でcredentials.digしなくてはいけない。
username: username
password: <%= Rails.application.credentials.dig(:db, :pw) %>
# 以下のようにしない
# password: Rails.application.credentials.dig(:db, :pw)
ActiveStorageなどの設定でもERBタグで囲んであるので、単純なミス。。
考察
ERBタグで囲わないと、ymlファイル内のRails.application.credentials.digメソッドが解決されずにリテラルとして評価されてしまうということなのだと思われる。
ただ、MySQLへ接続しに行くところのソースを見ると以下のようにHashで値をとってきている。
module Mysql2
module Util
#
# Rekey a string-keyed hash with equivalent symbols.
#
def self.key_hash_as_symbols(hash)
return nil unless hash
Hash[hash.map { |k, v| [k.to_sym, v] }]
end
ERBタグで囲った時の変数解決はどんな場合に実施されるのか? が不明
(単純にRailsアプリ内からファイルが読まれるときにはいつも行われるのか?)
詳しい方がいらっしゃったら教えていただけると幸いです。