Ruby on rails 无法创建FactoryGirl';s模型工厂
我对遗留项目有这种情况。假设我有rails模型:Ruby on rails 无法创建FactoryGirl';s模型工厂,ruby-on-rails,ruby,rspec,factory-bot,database-cleaner,Ruby On Rails,Ruby,Rspec,Factory Bot,Database Cleaner,我对遗留项目有这种情况。假设我有rails模型: rails g model entity name:string 在该模型中,存在主实体常量: class Entity < ActiveRecord::Base MAIN_ENTITY_ID = 1 MAIN_ENTITY = Entity.find(MAIN_ENTITY_ID) end 当我在内部测试中运行create(:entity)时,我得到以下错误: Failure/Error:MAIN\u ENTITY=ENT
rails g model entity name:string
在该模型中,存在主实体
常量:
class Entity < ActiveRecord::Base
MAIN_ENTITY_ID = 1
MAIN_ENTITY = Entity.find(MAIN_ENTITY_ID)
end
当我在内部测试中运行create(:entity)
时,我得到以下错误:
Failure/Error:MAIN\u ENTITY=ENTITY.find(MAIN\u ENTITY\u ID)
ActiveRecord::RecordNotFound:
找不到“id”=1的实体
如何在不重构代码并保持MAIN\u实体
不变的情况下修复此问题?不重构的解决方案(hack)
在访问类的静态上下文之前初始化Ruby常量。所以,当您调用<代码>实体代码>类(手动或通过使用FactoryGirl)时,后台会出现SQL查询,它试图查找id=1的记录
在生产环境中,这段代码是有效的,但是当您编写测试时,您的数据库通常会在每次测试用例运行后进行清理(rspec的it
)。所以,解决方案是在空数据库中运行每个测试用例之前创建“主实体”:
# Your DatabaseCleaner initializer file
RSpec.configure do |config|
# ...
config.around(:each) do |example|
DatabaseCleaner.cleaning do
FactoryGirl.create_main_entity
example.run
end
end
end
在create\u main\u entity
方法中,我们有一个限制:我们不能使用entity.create
或entity.new
方法,所以我们应该使用更低级的解决方案:我们需要将插入查询直接插入数据库。我会像这样重写你的实体.rb
-工厂:
FactoryGirl.define do
factory :entity do
name { FFaker::Company.name }
end
end
module FactoryGirl
def self.create_main_entity
connection = ActiveRecord::Base.connection
values = {
id: 1,
name: 'MAIN ENTITY',
created_at: Time.now.to_s(:db),
updated_at: Time.now.to_s(:db)
}
sql = <<-SQL
INSERT INTO entities (#{values.keys.map {|k| k.to_s}.join(', ')})
VALUES(#{values.values.map{"'%s'"}.join(', ')})
SQL
connection.insert(sql % values.values)
end
end
我在这里使用了记忆@@main_entity | |=…
来避免对每个实体执行相同的SELECT查询。main_entity
调用。并且最好不要使代码依赖于实体的id
。如果可能,请使用一些其他唯一属性,例如slug
,title
,等等。任何全局唯一的属性。同意您的意见,@JagdeepSingh,在某些情况下,id
可以更改。例如,我们有两个相同的结构化数据库(同一家公司的两个附属公司),有一天我们需要将这两个数据库合并到一个数据库中。因此,当db2.Entity
合并到db1.Entity
中时,id
-s将更改db1.Entity
。还有其他一些类似的情况,比如将数据库的一部分转储到json/xml,以便将这些数据导入其他地方。
FactoryGirl.define do
factory :entity do
name { FFaker::Company.name }
end
end
module FactoryGirl
def self.create_main_entity
connection = ActiveRecord::Base.connection
values = {
id: 1,
name: 'MAIN ENTITY',
created_at: Time.now.to_s(:db),
updated_at: Time.now.to_s(:db)
}
sql = <<-SQL
INSERT INTO entities (#{values.keys.map {|k| k.to_s}.join(', ')})
VALUES(#{values.values.map{"'%s'"}.join(', ')})
SQL
connection.insert(sql % values.values)
end
end
class Entity < ActiveRecord::Base
MAIN_ENTITY_ID = 1
def self.main_entity
@@main_entity ||= Entity.find(MAIN_ENTITY_ID)
end
end