Ruby on Rails删除具有外键的灯具 [英] Ruby on Rails deleting fixtures with foreign keys

查看:62
本文介绍了Ruby on Rails删除具有外键的灯具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用使用外键的固定装置设置测试时遇到了麻烦!如果有人可以帮助我理解这一点,我将非常感激.

I'm having trouble setting up the tests with fixtures that use foreign keys! And I would be much appreciated if someone could help me understand this.

例如,假设:user_type模型具有对:role模型的引用,则当执行测试时,将删除测试数据库中的所有数据以再次重新插入,Rails会从角色模型,而不是先从:user_type删除数据,然后才从:role删除数据.

Let's say for example the :user_type model has a reference to the :role model, when tests get executed, and all the data in the test db is deleted to be again re-inserted, Rails deletes the data from the role model first, instead of deleting the data first from the :user_type and only then from :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清理数据库(此时仍为空,因此没有违反约束的情况),然后插入了来自Fixtures的数据,并且测试运行良好. 下次我尝试运行测试时,它们将失败,因为当Rails开始从数据库中删除数据时,它将以角色模型/表而不是user_type开始!因为在这些模型上定义的外键会发生冲突,因为user_type仍引用模型表中的数据!

When the tests ran for the first time, everything goes ok. Rails cleans the database (in this point is still empty, so there is no constraint violations), then the data from the fixtures gets inserted, and the tests run fine. The next time I try to run the tests they will fail because when rails starts to delete the data from the database, it starts with the role model/table instead of the user_type! Because foreign keys where defined on these models a violation will occur because user_type is still referring to data in the model table!

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

How should this be done properly? Is there any mechanism to tell rails the order to destroy the fixture data? I am using RubyOnRails 4 and Firebird 2.5 by the way.

几天来我一直在为此苦苦挣扎,但我做不到!

I have been struggling with this for a few days and I haven’t been able to do it right!

提前谢谢!

推荐答案

我遇到了类似的问题,但是我使用PostgreSQL.我正在发布我的解决方案,希望能够为Firebird(我个人未使用过)提供类似的解决方案.

I encountered a similar problem, but I use PostgreSQL. I am posting my solution with the hope that an analogous solution exists for Firebird (which I have not personally used).

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

As you mentioned, when Rails executes the test suite, it starts by deleting all of the data in the database tables. This is tricky in the presence of foreign key constraints. In theory, one way to handle these constraints would be to figure out an appropriate order in which to delete records.

但是,至少对于PostgreSQL而言,Rails通过暂时禁用触发器来避免该问题,否则将避免违反这些外键约束.它通过以下两个(可能是特定于供应商的)SQL命令来执行此操作,这些命令在DELETE命令之前和之后执行:

However, at least for PostgreSQL, Rails actually sidesteps the issue by temporarily disabling the triggers which would otherwise prevent violation of these foreign key constraints. It does this with the following (probably vendor-specific) pair of SQL commands, executed before and after the DELETE commands:

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

有一个陷阱:只有超级用户角色(在此上下文中,角色"基本上表示用户")才能执行这些命令.实际上,除非Rails使用具有超级用户特权的PostgreSQL角色,否则它无法运行测试.也许Firebird也有超级用户?

There's a catch: only a superuser role (where "role" basically means "user" in this context) can execute these commands. Effectively, Rails can't run tests unless it is using a PostgreSQL role with the superuser privilege. Maybe Firebird has superusers, too?

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

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

To grant superuser to a user (only do this on your test or development database)

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

Run this SQL statement: ALTER USER myuser WITH SUPERUSER;

这是在没有超级用户特权的情况下尝试进行测试时从Rails 4.2.4版本开始出现的错误消息:

This is the error message that appears as of Rails 4.2.4 when attempting to test without superuser privilege:

ActiveRecord :: InvalidForeignKey:PG :: ForeignKeyViolation: 错误:表"tablename"上的更新或删除违反了外键 约束

ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: update or delete on table "tablename" violates foreign key constraint

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

In a future version of Rails, this more specific error message will be shown:

警告:Rails无法禁用参照完整性. 这很可能是由于缺少权限导致的. Rails需要超级用户特权才能禁用引用完整性.

WARNING: Rails was not able to disable referential integrity. This is most likely caused due to missing permissions. Rails needs superuser privileges to disable referential integrity.

请参见rails/rails 提交72c1557

See rails/rails commit 72c1557 and PR #17726 for more details.

这篇关于Ruby on Rails删除具有外键的灯具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆