Ruby on Rails用外键删除灯具

时间:2015-06-09 10:40:36

标签: ruby-on-rails ruby-on-rails-4 testing fixtures

我在使用使用外键的灯具设置测试时遇到了问题!如果有人能帮助我理解这一点,我将不胜感激。

例如,假设:user_type模型引用了:role模型,当执行测试时,测试数据库中的所有数据都被删除以再次重新插入,Rails删除首先是来自角色模型的数据,而不是先从:user_type删除数据,然后再从:role删除数据。

灯具:

#roles.yml
technical:
  name: 'Technical'
  obs: 'User Role for technical / maintenance users!'


#user_types.yml
technic:
  role: technical
  name: 'Technic'
  is_admin: true

测试:

#app/test/models/role_test.rb
require 'test_helper'

class RoleTest < ActiveSupport::TestCase
  fixtures :roles

  test 'save Role without name' do
    data = Role.new()
    data.valid?
    assert data.errors.added?(:name, :blank), 'Role saved without name!'
  end
end


#app/test/models/user_type_test.rb
require 'test_helper'

class UserTypeTest < ActiveSupport::TestCase
  fixtures :user_types

  test 'save User Type without role_id' do
    data = UserType.new(:name => 'public')
    data.valid?
    assert data.errors.added?(:role_id, :blank), 'User Type saved without role'
  end
end

当测试第一次运行时,一切正常。 Rails清理数据库(此时仍为空,因此没有违反约束),然后插入夹具中的数据,测试运行正常。 下次我尝试运行测试时它们会失败,因为当rails开始从数据库中删除数据时,它会以角色模型/表而不是user_type开头!因为在这些模型上定义的外键会发生违规,因为user_type仍然引用模型表中的数据!

如何正确完成? 是否有任何机制告诉轨道销毁夹具数据的顺序?我顺便使用RubyOnRails 4和Firebird 2.5。

我一直在努力解决这个问题,但我无法做到这一点!

提前谢谢!

1 个答案:

答案 0 :(得分:17)

我遇到了类似的问题,但我使用的是PostgreSQL。我发布我的解决方案,希望Firebird存在一个类似的解决方案(我没有亲自使用过)。

正如您所提到的,当Rails执行测试套件时,它首先删除数据库表中的所有数据。在存在外键约束时这很棘手。理论上,处理这些约束的一种方法是找出删除记录的适当顺序。

然而,至少对于PostgreSQL,Rails实际上通过暂时禁用触发器来避开该问题,否则会阻止违反这些外键约束。它使用以下(可能是特定于供应商的)SQL命令对执行此操作,在DELETE命令之前和之后执行:

ALTER TABLE tablename DISABLE TRIGGER ALL
ALTER TABLE tablename ENABLE TRIGGER ALL

有一个问题:只有超级用户角色(其中&#34;角色&#34;基本上意味着&#34;用户&#34;在此上下文中)可以执行这些命令。实际上,除非使用具有超级用户权限的PostgreSQL角色,否则Rails无法运行测试。也许Firebird也有超级用户?

有这个问题的PostgreSQL用户的附注:

向用户授予超级用户权限(仅在测试或开发数据库上执行此操作)

运行此SQL语句:ALTER USER myuser WITH SUPERUSER;

这是尝试在没有超级用户权限的情况下进行测试时从Rails 4.2.4开始显示的错误消息:

  

ActiveRecord :: InvalidForeignKey:PG :: ForeignKeyViolation:   错误:更新或删除表&#34; tablename&#34;违反外键   约束

在未来的Rails版本中,将显示更具体的错误消息:

  

警告:Rails无法禁用参照完整性。   这很可能是由于缺少权限造成的。   Rails需要超级用户权限才能禁用参照完整性。

有关详细信息,请参阅rails / rails commit 72c1557PR #17726