LoginSignup
0
0

More than 1 year has passed since last update.

db:create で ActiveRecord::NoDatabaseError factory_bot_rails の原因が factory_bot で モデル.new しているから?

Posted at

はじめに

製作中のアプリケーションにて、一度データベースを消して、再度作り成そうとしたところ、 NoDatabaseError が発生しました。
rails db:create を実行しているのに、 NoDatabaseError? と思いましたが、エラーの内容を見る限りfactory_botに関係があることだけはわかります。

console
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 をコメントアウトすることで、エラーが出なくなります。

(修正前)spec/factories/article_tag.rb
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
(修正後)spec/factories/article_tag.rb
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
(修正後)spec/models/article_tag_spec.rb
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も読み込んでいます。

console
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だと思います。

factory_bot_rails-6.2.0/lib/factory_bot_rails/railtie.rb
    config.after_initialize do |app|
      FactoryBot.find_definitions
      Reloader.new(app).run
    end

Reloader.new(app).runで呼び出されるのは、ログから考えると
factory_bot本体のdefault.rbdefineが呼び出されています。
そしてnew.instance_evalで、factory_botの定義ファイルが実行されるようです。
その結果active_recordが呼び出され、データベースを作っていないためエラーが発生しているようです。

factory_bot-6.2.0/lib/factory_bot/syntax/default.rb
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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0