はじめに
Rails 6 に追加された新機能を試す第112段。 今回は、database.yml warning
編です。
Rails 6 では、複数データベースに対応していますが、 database.yml
ファイルで複雑なERBが使われていると警告が出るようになっています。
Ruby 2.6.5, Rails 6.0.1 で確認しました。 (Rails 6.0.0 でこの修正が入ったようです。)
$ rails --version
Rails 6.0.1
今回は、警告を出すために、 環境変数 DB によって、 MySQLデータベースかPostgreSQLデータベースにアクセスを切り変えるということで試してみたいと思います。
複数データベースの機能は使いません。
Rails プロジェクトを作成する
$ rails new rails_sandbox
$ cd rails_sandbox
Gemfile に mysql2 と pg を追加する。
MySQL と PostgreSQL どちらでも接続できるように、 Gemfile に mysql2 と pg を追加します。
gem 'pg', '>= 0.18', '< 2.0'
gem 'mysql2'
bundle install を実行します。
$ bundle install
database.yml ファイルを編集する
database.yml
を変更します。
MySQL 用の接続設定と PostgreSQL 用の接続設定を追加します。
環境変数によって、接続を切り変えられるようにします。
ここで、ポイントは、 <<: *<%= ENV.fetch("DB") { 'postgresql' } %>
となっている部分です。
この記述によって警告が出るようになります。
mysql: &mysql
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: db_mysql
postgresql: &postgresql
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: db_postgresql
user: <%= ENV.fetch("POSTGRES_USER") %>
password: <%= ENV.fetch("POSTGRES_PASSWORD") %>
development:
<<: *<%= ENV.fetch("DB") { 'postgresql' } %>
database: app_development
...
test:
<<: *<%= ENV.fetch("DB") { 'postgresql' } %>
database: app_test
...
production:
<<: *<%= ENV.fetch("DB") { 'postgresql' } %>
database: app_production
...
スクリプトを作成する
確認のためだけなのですが、 database.yml を ERB でパースして結果を出力するスクリプトを書いておきます。
yml = ERB.new(File.read(Rails.root.join('config/database.yml')))
print yml.result
スクリプトを実行する
スクリプトを実行します。特にエラーもなくパースできています。
development:
の次の行が、 <<: *postgresql
と処理できていることに注意してください。
$ bin/rails runner scripts/parse_database_yml.rb
Running via Spring preloader in process 104
mysql: &mysql
adapter: mysql2
...
postgresql: &postgresql
adapter: postgresql
...
development:
<<: *postgresql
database: app_development
...
db:create を実行する
db:create
を実行します。
Rails couldn't infer whether you are using multiple databases from your database.yml ... please simplify your ERB.
と警告が出ます
$ bin/rails db:create
Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB.
Created database 'app_development'
Created database 'app_test'
なぜ警告が出るのか
複数データベースに対応するために、 Rails は、 boot 完了する前に、 database.yml
を読んで、task を生成しているそうです。task 生成する時点では、 ERB を使っておらず DummyCompiler を使って解析しており、この DummyCompiler では処理できない場合に警告を出すようにしたということらしいです。
どうすれば良いのか
結論としては、ERB の部分を警告が出ないように書き変えれば良いということになります。
では、一般的にどう書き変えれば良いのかは、筆者にもわかっていません。
ワーニングを出ないように修正する
今回の場合は、以下のように書き変えることで警告が出ないようにすることができました。
default
を追加して if
文使って切り変えるようにして、 development
などの環境では、 << *default
を使って ERB を使わないように修正しました。
mysql: &mysql
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: db_mysql
postgresql: &postgresql
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: db_postgresql
user: <%= ENV.fetch("POSTGRES_USER") %>
password: <%= ENV.fetch("POSTGRES_PASSWORD") %>
default: &default
<% database = ENV.fetch("DB"){ 'postgresql' } %>
<% if database == 'postgresql' %>
<<: *postgresql
<% else %>
<<: *mysql
<% end %>
development:
<<: *default
database: app_development
...
test:
<<: *default
database: app_test
...
production:
<<: *default
database: app_production
...
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try112_warn_database_yml - 警告が出る方
https://github.com/suketa/rails_sandbox/tree/try112_warn_database_yml_fix - 警告が出ないように修正した方