Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 无法创建FactoryGirl';s模型工厂_Ruby On Rails_Ruby_Rspec_Factory Bot_Database Cleaner - Fatal编程技术网

Ruby on rails 无法创建FactoryGirl';s模型工厂

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模型:

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