ruby-on-rails Ruby on Rails删除带有外键的fixture

q3aa0525  于 2023-10-21  发布在  Ruby
关注(0)|答案(2)|浏览(142)

我在设置使用外键的fixture的测试时遇到了问题!如果有人能帮助我理解这一点,我将不胜感激。
例如,: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会清理数据库(此时数据库仍然是空的,所以没有违反约束),然后插入来自fixture的数据,测试运行正常。下一次我尝试运行测试时,它们会失败,因为当rails开始从数据库中删除数据时,它从角色模型/表开始,而不是user_type!因为在这些模型上定义的外键会发生冲突,因为user_type仍然引用模型表中的数据!
这应该如何正确地完成?有没有什么机制可以告诉rails销毁fixture数据的顺序?我正在使用RubyOnRails 4和Firebird 2.5。
我已经挣扎了几天了,我还没有能够做到这一点的权利!
在此先谢谢您!

nkhmeac6

nkhmeac61#

我遇到了类似的问题,但我使用PostgreSQL。我发布我的解决方案,希望有一个类似的解决方案存在的火鸟(我没有亲自使用)。
正如您提到的,当Rails执行测试套件时,它首先删除数据库表中的所有数据。在存在外键约束的情况下,这是很棘手的。理论上,处理这些约束的一种方法是找出删除记录的适当顺序。
然而,至少对于PostgreSQL来说,Rails实际上通过暂时禁用触发器来回避这个问题,否则会防止违反这些外键约束。它使用以下(可能是特定于供应商的)一对SQL命令来实现这一点,这些命令在SQL命令之前和之后执行:

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

有个问题只有超级用户角色(其中“角色”在此上下文中基本上表示“用户”)可以执行这些命令。实际上,Rails不能运行测试,除非它使用具有超级用户权限的PostgreSQL角色。也许火鸟也有超级用户?

  • 对于有此问题的PostgreSQL用户的边注:*

向用户授予超级用户(仅对测试或开发数据库执行此操作)
运行以下SQL语句:ALTER USER myuser WITH SUPERUSER;
这是从Rails 4.2.4开始尝试在没有超级用户权限的情况下进行测试时出现的错误消息:
ActiveRecord::InvalidForeignKey:PG::ForeignKeyViolation:错误:更新或删除表“tablename”违反了外键约束
在Rails的未来版本中,将显示更具体的错误消息:
Rails无法禁用引用完整性。这很可能是由于缺少权限造成的。Rails需要超级用户权限来禁用引用完整性。
有关详细信息,请参阅rails/rails commit 72c1557PR #17726

ruyhziif

ruyhziif2#

我在开发Ruby on Rails应用程序时遇到了同样的问题。
我有一个user模型,它有一个连接表到rolepermission模型:

用户型号

class User < ApplicationRecord
  has_many :user_permissions, dependent: :destroy
  has_many :permissions, through: :user_permissions, dependent: :destroy
  has_many :user_roles, dependent: :destroy
  has_many :roles, through: :user_roles, dependent: :destroy
end

榜样

class Role < ApplicationRecord
  has_many :role_permissions, dependent: :destroy
  has_many :permissions, through: :role_permissions, dependent: :destroy
  has_many :user_roles, dependent: :destroy
  has_many :roles, through: :user_roles, dependent: :destroy
end

权限模型

class Role < ApplicationRecord
  has_many :user_permissions, dependent: :destroy
  has_many :permissions, through: :user_permissions, dependent: :destroy
  has_many :role_permissions, dependent: :destroy
  has_many :permissions, through: :role_permissions, dependent: :destroy
end

但是,当我尝试删除应用程序上的所有usersrolespermissions时,同时使用以下命令进行开发:

Permission.delete_all
Role.delete_all
User.delete_all

我得到的错误:
轨道中止!ActiveRecord::InvalidForeignKey:PG::ForeignKeyViolation:错误:对表“permissions”的更新或删除违反了对表“role_permissions”的外键约束“fk_rails_439e640a3f”。Key(id)=(1)仍然从表“role_permissions”引用。

这是我如何修复它

问题是delete_all方法没有在关联对象上调用删除操作,因为我们只在单独的资源(UsersPermissionsRoles)上直接调用它。我们还需要专门在连接表上调用它。
我简单地修改了delete_all操作,在使用以下命令运行delete_all操作之前,首先删除每个模型的连接表关联:

RolePermission.delete_all
Permission.delete_all

UserRole.delete_all
Role.delete_all

User.delete_all

这一次一切都很顺利。

相关问题