簡體   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