はじめに
製作中のアプリケーションにて、一度データベースを消して、再度作り成そうとしたところ、 NoDatabaseError
が発生しました。
rails db:create
を実行しているのに、 NoDatabaseError
? と思いましたが、エラーの内容を見る限りfactory_bot
に関係があることだけはわかります。
username@pc article_app % rails db:drop
Dropped database 'article_app_development'
Dropped database 'article_app_test'
username@pc article_app % rails db:create
rails aborted!
ActiveRecord::NoDatabaseError: Unknown database 'article_app_development'
/Users/username/projects/article_app/spec/factories/article_tag.rb:2:in `block in <main>'
/Users/username/projects/article_app/spec/factories/article_tag.rb:1:in `<main>'
/Users/username/projects/article_app/config/environment.rb:5:in `<main>'
bin/rails:9:in `<main>'
Caused by:
Mysql2::Error: Unknown database 'article_app_development'
/Users/username/projects/article_app/spec/factories/article_tag.rb:2:in `block in <main>'
/Users/username/projects/article_app/spec/factories/article_tag.rb:1:in `<main>'
/Users/username/projects/article_app/config/environment.rb:5:in `<main>'
bin/rails:9:in `<main>'
Tasks: TOP => db:create => db:load_config => environment
(See full trace by running task with --trace)
結論
発生原因は factory_bot 内で モデル.new している からでした。
ダメなfactory_botの記述をしていたということです。
次のように記述していました。問題は2行目です。
article = article.new
をコメントアウトすることで、エラーが出なくなります。
FactoryBot.define do
article = article.new
factory :article_tag do
title { Faker::Lorem.sentence }
category_id { Faker::Number.within(range: 1..3) }
tags { Faker::Lorem.words.join(',') }
content do
experience.content = '<div>asdf</div>'
experience.content
end
end
end
FactoryBot.define do
factory :article_tag do
title { Faker::Lorem.sentence }
category_id { Faker::Number.within(range: 1..3) }
tags { Faker::Lorem.words.join(',') }
end
end
require 'rails_helper'
RSpec.describe ArticleTag, type: :model do
before do
@article_tag = FactoryBot.build(:article_tag)
@article_tag.content = '<div>rspec test data</div>'
理由
(英語ですら似た現象が出てこなかったので、自身は有りませんが、誰かしらの参考になればと思っています。)
次の内容はrails db:create
コマンドを実行するときに、--trace
を加えた場合の出力内容です。
この内容から、rails db:create
コマンドは実行した後、まず設定ファイルや関連するGemも読み込んでいます。
username@pc article_app % rails db:create --trace
** Invoke db:create (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
rails aborted!
ActiveRecord::NoDatabaseError: Unknown database 'article_app_development'
...
...(長いので割愛)
...
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.4.1/lib/active_record/attribute_methods.rb:171:in `has_attribute?'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.4.1/lib/active_record/inheritance.rb:55:in `new'
/Users/username/projects/article_app/spec/factories/article_tag.rb:2:in `block in <main>'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/syntax/default.rb:37:in `instance_eval'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/syntax/default.rb:37:in `run'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/syntax/default.rb:7:in `define'
/Users/username/projects/article_app/spec/factories/article_tag.rb:1:in `<main>'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:60:in `load'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:60:in `load'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/find_definitions.rb:20:in `block (2 levels) in find_definitions'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/find_definitions.rb:19:in `each'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/find_definitions.rb:19:in `block in find_definitions'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/find_definitions.rb:15:in `each'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot-6.2.0/lib/factory_bot/find_definitions.rb:15:in `find_definitions'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/factory_bot_rails-6.2.0/lib/factory_bot_rails/railtie.rb:22:in `block in <class:Railtie>'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.4.1/lib/active_support/lazy_load_hooks.rb:68:in `block in execute_hook'
...
...(長いので割愛)
...
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.9.1/lib/bootsnap/
/Users/username/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
bin/rails:9:in `<main>'
Tasks: TOP => db:create => db:load_config => environment
その過程でfactory_bot_rails
が読み込まれています。
次のログから考えて、このFactoryBot.find_definitions
で定義ファイルを読み込んで、ここまでが正常だと思います。
今回の問題が発生したのは次のReloader.new(app).run
だと思います。
config.after_initialize do |app|
FactoryBot.find_definitions
Reloader.new(app).run
end
Reloader.new(app).run
で呼び出されるのは、ログから考えると
factory_bot本体のdefault.rb
のdefine
が呼び出されています。
そしてnew.instance_eval
で、factory_botの定義ファイルが実行されるようです。
その結果active_record
が呼び出され、データベースを作っていないためエラーが発生しているようです。
module FactoryBot
module Syntax
module Default
include Methods
def define(&block)
DSL.run(block)
end
...
class DSL
...
def self.run(block)
new.instance_eval(&block)
end
参考
github: thoughtbot/factory_bot
github: thoughtbot/factory_bot_rails
rubyドキュメント: instance_eval