无与 Rails 个固定装置的关联...如何修复?

Nil Associations with Rails Fixtures... how to fix?

我有一个使用 rspec/fixtures 的 Rails 5.1 项目,但我无法让固定装置加载与 belongs_to/has_one/has_many 关联的对象:我请求固定装置的对象返回了它的_id 列填充了看似随机的数字,ActiveRecord 将关联视为 nil。这发生在具有许多关联的大 类 以及只有几个字段的小数据 类 上。

如果在我的测试代码中,我将这些关联分配给正常的 Ruby 代码,对象将正常运行并且我的测试通过。但是,当通过固定装置加载相同的数据时,关联的记录不可用,并且需要跨越关联的数据的测试失败。

例如,这里有两个受影响的 类:

#app/models/location.rb
class Location < ActiveRecord::Base
  has_many :orders
  has_many :end_user
  belongs_to :retailer
  belongs_to :depot
end

#app/models/retailer.rb
class Retailer < ActiveRecord::Base
    has_many :locations
end

这里有两个对应的灯具文件:

#spec/fixtures/locations.yml
loc_paris:
  retailer: ret_europe (Retailer)
  name: "Paris"
  nickname: "paris"

loc_washington:
  retailer: ret_usa (Retailer)
  name: "Washington"
  nickname: "washington"

#spec/fixtures/retailers.yml
ret_europe:
  name: "AcmeCo France"
  nickname: "acmecofr"
  currency_type: "EUR"

ret_usa:
  name: "AcmeCo USA"
  nickname: "acmecousa"
  currency_type: "USD"

根据以上数据,运行 pp locations(:loc_paris) 结果:

#<Location:0x0000000006eee1d8
 id: 35456173,
 name: "Paris",
 nickname: "paris",
 retailer_id: 399879241,
 created_at: Wed, 23 May 2018 22:39:56 UTC +00:00,
 updated_at: Wed, 23 May 2018 22:39:56 UTC +00:00>

这些 id 号通过多次调用是一致的,至少在相同的 RSpec 上下文中。 (我把 pp locations(:loc_paris) 放在 let 块中。)然而 pp locations(:loc_paris).retailer returns nil.

我尝试使用 FactoryBot,但我们不得不放弃它。我试图给 fixtures 一个诚实的摇晃,但似乎我们最好只是在实际测试代码中构建数据对象......因为该解决方案没有抱怨:/

我是不是做错了什么?我们是不是对固定装置要求太多了?

谢谢!

汤姆

灯具问题

查看您的操作,locations(:loc_paris) 会找到 locations.yml 中描述的记录,但 locations(:loc_paris).retailer 不会。

Rails 协会是这样工作的:

locations(:loc_paris).retailer 将查找 locations(:loc_paris) 记录中提到的带有 retailer_idretailer。在你的情况下 retailer_id: 399879241 而这个 id 没有 reseller 这就是为什么 returns Nil.

解法: 像这样描述灯具:

#spec/fixtures/locations.yml
loc_paris:
  retailer_id: 1
  name: "Paris"
  nickname: "paris"

loc_washington:
  retailer_id: 2
  name: "Washington"
  nickname: "washington"

#spec/fixtures/retailers.yml
ret_europe:
  id: 1
  name: "AcmeCo France"
  nickname: "acmecofr"
  currency_type: "EUR"

ret_usa:
  id: 2
  name: "AcmeCo USA"
  nickname: "acmecousa"
  currency_type: "USD"

现在,locations(:loc_paris).retailer 将查找 locations(:loc_paris) 记录中提到的 retailer_id 的零售商,即 retailer_id: 1 并且有一个经销商 ret_europe id问题已解决

当您 运行 rspec 时,首先 rspec 使用一些自动生成的 id 值将这些灯具保存到您的数据库中(如果 id 未明确提供),这就是为什么 idreseller_id 是一些随机值 。如果你不希望 locations.yml 记录的 id 是一些随机值,你可以像这样自己提供:

loc_paris:
  id: 1
  retailer_id: 1
  name: "Paris"
  nickname: "paris"

提示: 作为 rspec 运行s 在 test 环境中(在 app/spec/rails_helper.rb 中提到)和我之前提到的每当你 运行 rspec,首先它将灯具保存到您的数据库中。如果您的 localtest 数据库相同,fixtures 将替换您数据库的实际数据库记录。在您的情况下,locationsresellers table 记录中的记录将被完全擦除并替换为这些固定装置。因此,为 test 环境创建不同的数据库。

希望这个回答对您有所帮助