2

我有两个相互依赖的模型,帐户和用户。一个账户总是由一个用户创建的,它的 id 因此存储在账户的 creator_id 属性中,并且一个用户必然属于一个账户(但对属于一个账户的用户数量没有限制),该信息存储在用户的account_id 属性。同一用户可以创建不同的帐户。

我以这种方式表达了这些规则:

用户型号:

belongs_to :account, inverse_of: :users
has_many :created_accounts, class_name: "Account", :foreign_key => "creator_id"

账户模式:

 belongs_to :creator, class_name: 'User', optional: true
 has_many :users, inverse_of: :account

由于它们是相互依赖的,我使用了一种肮脏的解决方法来实例化它们:我首先创建帐户,然后在该操作之后强制用户创建他们的个人资料,并且他们的 user_id 在更新中作为 creator_id 添加到帐户中。

这就是我在 Account 模型中拥有的原因:

validate :require_actual_creator_id, on: :update
------------------------------------------------
 def require_actual_creator_id
    User.find(creator_id)
  end

我正在研究一个只涉及用户模型的身份验证系统,所以我将这些行注释掉,直到昨天我取消注释它们。

我运行 db:migrate:reset, db:seed 和 db:migrate RAILS_ENV=test 没有任何问题,两个模型在控制台中都有正常的行为,但是当涉及到夹具(例如测试或 db:fixtures:load)时,我收到以下错误:

NoMethodError: undefined method `id' for nil:NilClass
/home/vincent/workspace/bam-rails/test/fixtures/users.yml:16:in `get_binding'

这是一个导致问题的典型夹具,第 16 行是注释的:

michael:
  id: 1
  handle: Michael Example
  email: michael@example.com
  encrypted_password: <%= User.generate_encrypted_token('password') %>
  role_id: <%= User::ADMIN %>
  is_activated: true
  activated_at: <%= DateTime.now %>
  #account_id: <%#= Account.first.id %>

当我评论最后一行时,就没有问题了。但是,我想为我的测试加载正确的夹具,因为例如在这里创建的用户是无效的。

我在这篇文章中读到,固定装置按字母顺序加载。如果这是正确的,我不明白为什么我必须评论这一行,因为帐户应该在用户之前加载。

我发现该解决方案可行,但它不是来自官方文档,而且它已经很老了,可以追溯到 2007 年。我担心这会从一天到另一天停止工作。

有谁知道如何在 Rails 5 中按自定义顺序正确加载固定装置,或者对我的问题有另一种解决方案?先感谢您。

4

1 回答 1

2

您遇到的问题完全源于您组织代码的方式。解决您创建第一个帐户的地方是您遇到问题的地方。因此,当您的用户被实例化时,您的帐户首先不存在,因为设备尚未加载;这一点我相信你是知道的。Fixtures 是出了名的脆弱,这就是为什么人们经常远离他们的代码越复杂。在这种情况下,尽管这会帮助您暴露代码异味,但无论何时订单或运行您的测试或基本的非测试用例特定设置都会导致问题,这意味着您的代码有问题。我建议您找到使用这种“肮脏工作”的方法。

现在,如果由于某种原因您与您的代码当前的组织方式结婚,我建议您可能切换到工厂女孩,它会给您更多的灵活性来控制您的模拟对象的实例化点,这样您就不会遇到这种情况问题。然而,我会说这只会让你继续沿着这条路走下去,这很可能只会导致更多的问题,你最好的选择是重新实现该功能。

于 2016-10-18T15:21:09.933 回答