我有两个相互依存的模型,帐户和用户。帐户始终由用户创建,其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添加到帐户中更新。
这就是我在帐户模型中的原因:
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 %>
当我评论最后一行时,已经没有问题了。但是,我想为我的测试加载适当的灯具,因为例如此处创建的用户无效。
我在this post中读到灯具按字母顺序加载。如果这是正确的,我无法理解为什么我要评论这一行,因为帐户应该在用户之前加载。
我发现that solution可以使用,但它不是来自官方文档,并且它已经很久了,可以追溯到2007年。我担心这会在一天到下一天停止工作。
有人知道如何在Rails 5中以自定义顺序正确加载灯具,还是有其他解决方案来解决我的问题? 提前谢谢。
答案 0 :(得分:2)
您遇到的问题完全源于您组织代码的方式。在您创建第一个帐户的地方工作就是您遇到问题的地方。因此,当您的用户被实例化时,您的帐户首先不存在,因为尚未加载灯具;我确信你知道这一点。众所周知,灯具很脆弱这就是为什么人们经常离开它们,代码越复杂。在这种情况下,虽然帮助您暴露代码气味,但只要订单或运行您测试或基本非测试用例特定设置导致问题意味着您的代码存在问题。我建议你找到一种方法来使用这种“肮脏的工作”。
现在如果由于某种原因你嫁给你的代码当前的组织方式我建议切换到factory girl,它会给你一点灵活性来控制模拟对象被实例化的点你不会遇到这个问题的方式。然而,我会说这只会让你继续沿着这条路走下去,这很可能会导致更多的问题,你最好的办法是重新实现这个功能。