简体   繁体   English

我应该在哪里创建共享的FactoryBot关联?

[英]Where should I create my shared FactoryBot associations?

I have a User model that has_one required Company . 我有一个has_one required CompanyUser模型。 Using FactoryBot, I want to create several users that share that same company. 我想使用FactoryBot创建共享同一公司的多个用户。 I saw some advice which I interpreted as suggesting I create Company objects within my FactoryBot.define do block, which I can use as attributes for my users: 我看到了一些建议 ,这些建议被解释为建议在FactoryBot.define do块中创建Company对象,可以将其用作用户的属性:

# In spec/factories/companies.rb
FactoryBot.define do
  factory :company do
    name { 'MyCompany' }
  end
end


# In spec/factories/users.rb
FactoryBot.define do
  company1 = FactoryBot.create(:company)  # this will be shared by several users

  factory :user1 do
    first_name { 'Joe' } 
    last_name { 'Smith' } 
    company_id { company1.id }
  end

  factory :user2 do
    first_name { 'Sam' } 
    last_name { 'Smith' } 
    company_id { company1.id }
  end
end

This appears to work at first, except when I need to re-create the database from scratch in a test container with rake db:create . 这似乎起初是可行的,除了当我需要使用rake db:create在测试容器中从头开始重新创建数据库时。 When rake runs, it seems to initialize my factories and the FactoryBot.create(:company) step tries to run, and there is no db schema in place, so it fails: 当rake运行时,似乎初始化了我的工厂,并且FactoryBot.create(:company)步骤尝试运行,并且没有适当的数据库模式,因此它失败了:

$ RAILS_ENV=test  bundle exec rake db:rebuild
rake aborted!
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "companies" does not exist
LINE 8:                WHERE a.attrelid = '"companies"'::regclass
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
                     c.collname, col_description(a.attrelid, a.attnum) AS comment
                FROM pg_attribute a
                LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
                LEFT JOIN pg_type t ON a.atttypid = t.oid
                LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
               WHERE a.attrelid = '"companies"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum

This makes me think that I'm trying to create these in the wrong place. 这使我认为我试图在错误的位置创建它们。

Where is the best place to set up shared associations like company1 for my test data so that it occurs after my app properly initializes and before my test suite is executed? 在哪里为我的测试数据设置像company1这样的共享关联的最佳位置是什么,以便它在我的应用正确初始化之后并且在我的测试套件执行之前发生?

FWIW, here's the error stack: FWIW,这是错误堆栈:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "companies" does not exist
LINE 8:                WHERE a.attrelid = '"companies"'::regclass
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
                     c.collname, col_description(a.attrelid, a.attnum) AS comment
                FROM pg_attribute a
                LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
                LEFT JOIN pg_type t ON a.atttypid = t.oid
                LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
               WHERE a.attrelid = '"companies"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:63:in `async_exec'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:63:in `block (2 levels) in query'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:62:in `block in query'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/abstract_adapter.rb:579:in `block (2 levels) in log'
/usr/local/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/abstract_adapter.rb:578:in `block in log'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/notifications/instrumenter.rb:23:in `instrument'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/abstract_adapter.rb:569:in `log'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:61:in `query'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:749:in `column_definitions'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/abstract/schema_statements.rb:113:in `columns'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/schema_cache.rb:69:in `columns'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/connection_adapters/schema_cache.rb:75:in `columns_hash'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/model_schema.rb:466:in `load_schema!'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/attributes.rb:234:in `load_schema!'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/attribute_decorators.rb:51:in `load_schema!'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/model_schema.rb:459:in `block in load_schema'
/usr/local/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/model_schema.rb:456:in `load_schema'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/model_schema.rb:346:in `attribute_types'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/attribute_methods.rb:230:in `has_attribute?'
/usr/local/bundle/gems/activerecord-5.2.0/lib/active_record/inheritance.rb:55:in `new'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/decorator/new_constructor.rb:9:in `new'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/decorator.rb:14:in `send'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/decorator.rb:10:in `method_missing'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/decorator/invocation_tracker.rb:11:in `method_missing'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/decorator.rb:14:in `send'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/decorator.rb:10:in `method_missing'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/configuration.rb:19:in `block in initialize'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/attribute_assigner.rb:48:in `instance_exec'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/attribute_assigner.rb:48:in `build_class_instance'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/attribute_assigner.rb:13:in `object'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/evaluation.rb:13:in `object'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/strategy/create.rb:9:in `result'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/factory.rb:43:in `run'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/factory_runner.rb:29:in `block in run'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/notifications.rb:170:in `instrument'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/factory_runner.rb:28:in `run'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
/builds/MyGroup/MyApp/spec/factories/users.rb:4:in `block in <main>'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/syntax/default.rb:49:in `instance_eval'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/syntax/default.rb:49:in `run'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/syntax/default.rb:7:in `define'
/builds/MyGroup/MyApp/spec/factories/users.rb:2:in `<main>'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `block in load'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:249:in `load_dependency'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `load'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/find_definitions.rb:20:in `block (2 levels) in find_definitions'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/find_definitions.rb:19:in `each'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/find_definitions.rb:19:in `block in find_definitions'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/find_definitions.rb:15:in `each'
/usr/local/bundle/gems/factory_bot-4.11.1/lib/factory_bot/find_definitions.rb:15:in `find_definitions'
/usr/local/bundle/gems/factory_bot_rails-4.11.1/lib/factory_bot_rails/railtie.rb:21:in `block in <class:Railtie>'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/lazy_load_hooks.rb:69:in `block in execute_hook'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/lazy_load_hooks.rb:62:in `with_execution_control'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/lazy_load_hooks.rb:67:in `execute_hook'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/lazy_load_hooks.rb:52:in `block in run_load_hooks'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/lazy_load_hooks.rb:51:in `each'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/lazy_load_hooks.rb:51:in `run_load_hooks'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/application/finisher.rb:75:in `block in <module:Finisher>'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/initializable.rb:32:in `instance_exec'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/initializable.rb:32:in `run'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/initializable.rb:61:in `block in run_initializers'
/usr/local/lib/ruby/2.5.0/tsort.rb:228:in `block in tsort_each'
/usr/local/lib/ruby/2.5.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
/usr/local/lib/ruby/2.5.0/tsort.rb:431:in `each_strongly_connected_component_from'
/usr/local/lib/ruby/2.5.0/tsort.rb:349:in `block in each_strongly_connected_component'
/usr/local/lib/ruby/2.5.0/tsort.rb:347:in `each'
/usr/local/lib/ruby/2.5.0/tsort.rb:347:in `call'
/usr/local/lib/ruby/2.5.0/tsort.rb:347:in `each_strongly_connected_component'
/usr/local/lib/ruby/2.5.0/tsort.rb:226:in `tsort_each'
/usr/local/lib/ruby/2.5.0/tsort.rb:205:in `tsort_each'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/initializable.rb:60:in `run_initializers'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/application.rb:361:in `initialize!'
/builds/MyGroup/MyApp/config/environment.rb:5:in `<main>'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi'
/usr/local/bundle/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:283:in `block in require'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:249:in `load_dependency'
/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:283:in `require'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/application.rb:337:in `require_environment!'
/usr/local/bundle/gems/railties-5.2.0/lib/rails/application.rb:520:in `block in run_tasks_blocks'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:271:in `block in execute'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:271:in `each'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:271:in `execute'
/usr/local/bundle/gems/bugsnag-6.8.0/lib/bugsnag/integrations/rake.rb:18:in `execute_with_bugsnag'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:213:in `block in invoke_with_call_chain'
/usr/local/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:193:in `invoke_with_call_chain'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:237:in `block in invoke_prerequisites'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:235:in `each'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:235:in `invoke_prerequisites'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:212:in `block in invoke_with_call_chain'
/usr/local/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:193:in `invoke_with_call_chain'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/task.rb:182:in `invoke'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:160:in `invoke_task'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:116:in `block (2 levels) in top_level'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:116:in `each'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:116:in `block in top_level'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:125:in `run_with_threads'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:110:in `top_level'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:83:in `block in run'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:186:in `standard_exception_handling'
/usr/local/bundle/gems/rake-12.3.1/lib/rake/application.rb:80:in `run'
/usr/local/bundle/gems/rake-12.3.1/exe/rake:27:in `<top (required)>'
/usr/local/bundle/bin/rake:23:in `load'
/usr/local/bundle/bin/rake:23:in `<top (required)>'

When you create objects in this way - they are created each time factories are initialised, no matter if they will be used in particular test run or not. 当您以这种方式创建对象时-每次工厂初始化时都会创建对象,无论是否在特定的测试运行中使用它们。

It's usually better to have independent factories and explicitly state in your tests that you want two users from same company: 通常最好有独立的工厂,并在测试中明确声明您希望来自同一公司的两个用户:

 let(:company){ create :company }
 let(:user1){ create :user, company: company }
 let(:user2){ create :user, company: company }

For cases when you do not care about exact relation and just want to reuse some valid value and avoid relations cascading - there's create_default workaround in test-prof gem (see more here ) 对于那些您不关心确切关系而只想重用一些有效值并避免关系级联的情况-在test-prof gem中有create_default解决方法(请参阅此处的更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM