调试导轨中夹具外键错误的技巧

Zac*_*ack 13 ruby ruby-on-rails fixtures

我的装置设置中出现外键错误,并且我对如何调试它感到困惑。

具体来说,我收到以下错误,但我知道标签存在:

RuntimeError: Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations.
Run Code Online (Sandbox Code Playgroud)

设置如下:我有用户、类别和条目。每个类别有一个用户,每个条目有 12 个类别。

有问题的参赛装置是

bob_2022_01_10:
  date: 2022-01-10
  segment: 3
  user: bob
  category_0: test
  # categories can be null, so I don't set category_1 through category_11 for this example.
Run Code Online (Sandbox Code Playgroud)

而且,如果我注释掉该category_0行,一切都会正常。

类别固定装置是

test:
  id: 100
  name: Test category
  user: bob
  parent_id: nil
Run Code Online (Sandbox Code Playgroud)

如果我注释掉 Entry 夹具中的违规行,我就可以test在其他测试中使用该夹具。(因此,我知道问题不在于我引用了不存在的夹具。)

我可以在测试中“手动”设置条目和类别之间的关系:

   entry = entries :bob_2022_01_10
   entry.category_0 = categories :test
Run Code Online (Sandbox Code Playgroud)

我还可以使用 Category_id 而不是夹具名称来设置夹具:

bob_2022_01_10:
  date: 2022-01-10
  segment: 3
  user: bob
  category_0_id: 100
Run Code Online (Sandbox Code Playgroud)

我想知道问题是否出在我设置外键的方式上Entry.rb

class Entry < ApplicationRecord

  LAST_SEGMENT = 11

  belongs_to :user

  validate :validate_category_owner
  
  (0..LAST_SEGMENT).each do |time_segment|
    belongs_to "category_#{time_segment}".to_sym, class_name: "Category", foreign_key: "category_#{time_segment}_id", optional: true
   end
Run Code Online (Sandbox Code Playgroud)

然而,这会很奇怪,因为除了夹具设置之外的所有东西都有效。

有什么想法我可能做错了什么吗?


如果有帮助,我也会包含架构:

ActiveRecord::Schema.define(version: 2022_01_15_023305) do

  create_table "categories", force: :cascade do |t|
    t.string "name"
    t.integer "order"
    t.integer "user_id", null: false
    t.integer "parent_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["parent_id"], name: "index_categories_on_parent_id"
    t.index ["user_id"], name: "index_categories_on_user_id"
  end

  create_table "entries", force: :cascade do |t|
    t.date "date"
    t.integer "segment"
    t.integer "user_id", null: false
    t.integer "category_0_id"
    t.integer "category_1_id"
    t.integer "category_2_id"
    t.integer "category_3_id"
    t.integer "category_4_id"
    t.integer "category_5_id"
    t.integer "category_6_id"
    t.integer "category_7_id"
    t.integer "category_8_id"
    t.integer "category_9_id"
    t.integer "category_10_id"
    t.integer "category_11_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["category_0_id"], name: "index_entries_on_category_0_id"
    t.index ["category_10_id"], name: "index_entries_on_category_10_id"
    t.index ["category_11_id"], name: "index_entries_on_category_11_id"
    t.index ["category_1_id"], name: "index_entries_on_category_1_id"
    t.index ["category_2_id"], name: "index_entries_on_category_2_id"
    t.index ["category_3_id"], name: "index_entries_on_category_3_id"
    t.index ["category_4_id"], name: "index_entries_on_category_4_id"
    t.index ["category_5_id"], name: "index_entries_on_category_5_id"
    t.index ["category_6_id"], name: "index_entries_on_category_6_id"
    t.index ["category_7_id"], name: "index_entries_on_category_7_id"
    t.index ["category_8_id"], name: "index_entries_on_category_8_id"
    t.index ["category_9_id"], name: "index_entries_on_category_9_id"
    t.index ["user_id"], name: "index_entries_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "fname"
    t.string "lname"
    t.string "email"
    t.string "password_digest"
    t.boolean "admin"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  add_foreign_key "categories", "categories", column: "parent_id"
  add_foreign_key "categories", "users"
  add_foreign_key "entries", "categories", column: "category_0_id"
  add_foreign_key "entries", "categories", column: "category_10_id"
  add_foreign_key "entries", "categories", column: "category_11_id"
  add_foreign_key "entries", "categories", column: "category_1_id"
  add_foreign_key "entries", "categories", column: "category_2_id"
  add_foreign_key "entries", "categories", column: "category_3_id"
  add_foreign_key "entries", "categories", column: "category_4_id"
  add_foreign_key "entries", "categories", column: "category_5_id"
  add_foreign_key "entries", "categories", column: "category_6_id"
  add_foreign_key "entries", "categories", column: "category_7_id"
  add_foreign_key "entries", "categories", column: "category_8_id"
  add_foreign_key "entries", "categories", column: "category_9_id"
  add_foreign_key "entries", "users"
end
Run Code Online (Sandbox Code Playgroud)

Lam*_*han 14

这里的问题是错误RuntimeError: Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations没有任何帮助,这实际上取代了真正的错误

  if ActiveRecord.verify_foreign_keys_for_fixtures && !conn.all_foreign_keys_valid?
     raise "Foreign key violations found in your fixture data..."
  end
Run Code Online (Sandbox Code Playgroud)

根据上面的代码,您可以禁用verify_foreign_keys_for_fixtures

# config/application.rb
config.active_record.verify_foreign_keys_for_fixtures = false
Run Code Online (Sandbox Code Playgroud)

或者找出背后的错误(db级别)。为此,您需要在all_foreign_keys_valid? 方法中手动运行 sql?多于

def all_foreign_keys_valid?
  sql = <<~SQL
  #....
  SQL

    begin
      transaction(requires_new: true) do
         execute(sql)
      end

      true
    # rescue ActiveRecord::StatementInvalid
    #    false
    rescue => e
      puts e # this will show the db level error
    end
end
Run Code Online (Sandbox Code Playgroud)

就我而言,数据库错误是permission denied ...,我需要将数据库用户授予 SUPERUSER,您的情况可能不一样。最后,提示:手动运行 sql 以找出根本原因。


小智 10

我今天也遇到了同样的问题。如果您在固定装置元素中设置了 ,id那么您只能通过固定装置元素的 id 来引用它,而不能通过名称来引用它。

因此,如果您在类别夹具中注释掉id: 100,那么您应该能够category_0: test在条目夹具中使用。