繁体   English   中英

Ruby on Rails 删除带有外键的设备

[英]Ruby on Rails deleting fixtures with foreign keys

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

例如,假设: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 仍然引用模型表中的数据!

这应该如何正确完成? 是否有任何机制可以告诉 rails 销毁夹具数据的顺序? 顺便说一下,我正在使用 RubyOnRails 4 和 Firebird 2.5。

我已经为此苦苦挣扎了几天,但我一直无法做到正确!

先感谢您!

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

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

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

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

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

有此问题的 PostgreSQL 用户的旁注:

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

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

这是 Rails 4.2.4 在没有超级用户权限的情况下尝试测试时出现的错误消息:

ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: 错误:更新或删除表“tablename”违反外键约束

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

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

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

我在处理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”细节:键(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

这次一切正常。

我希望这有帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM