0

我似乎遇到了某种循环关系,gem文档中的两个解决方案无法为我解决。请参见下面的示例。这是否意味着要以不同的方式完成?

有人会争辩说,因为一个对象没有另一个对象就无法真正持久化,它们应该只是一个模型。我认为最好将有关身份验证的所有逻辑提取到其单独的模型中,以免使用户膨胀。大多数情况下,凭据仅在创建会话时使用,而用户则一直在使用。

create_table "credentials", force: :cascade do |t|
  t.bigint "user_id", null: false
  ...
  t.index ["user_id"], name: "index_credentials_on_user_id"
end

add_foreign_key "credentials", "users"
class Credential < ApplicationRecord
  belongs_to :user, inverse_of: :credential
end

class User < ApplicationRecord
  has_one :credential, inverse_of: :user
  validates :credential, presence: true
end
Fabricator(:user_base, class_name: :user)

Fabricator(:user, from: :user_base) do
  credential
end

Fabricator(:credential) do
  user(fabricator: :user_base)
end
irb(main):001:0> Fabricate(:user)
  TRANSACTION (0.1ms)  BEGIN
  TRANSACTION (0.1ms)  ROLLBACK
Traceback (most recent call last):
        1: from (irb):1:in `<main>'
ActiveRecord::RecordInvalid (Validation failed: Credential can't be blank)
irb(main):002:0> Fabricate(:credential)
Traceback (most recent call last):
        2: from (irb):1:in `<main>'
        1: from (irb):2:in `rescue in <main>'
ActiveRecord::RecordInvalid (Validation failed: Credential can't be blank)
irb(main):003:0> Fabricate.build(:user).save
  TRANSACTION (0.2ms)  BEGIN
  User Create (0.8ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "fake@mail.com"], ["created_at", "2021-05-29 18:19:09.312429"], ["updated_at", "2021-05-29 18:19:09.312429"]]
  Credential Create (0.9ms)  INSERT INTO "credentials" ("user_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["user_id", 19], ["created_at", "2021-05-29 18:19:09.319411"], ["updated_at", "2021-05-29 18:19:09.319411"]]
  TRANSACTION (41.2ms)  COMMIT
=> true
4

2 回答 2

0

具有外键的模型(在本例中为 Credential)是需要保留 user_id 值的模型。这意味着在创建凭证之前需要有一个用户(在内存中或在数据库中)。这就是使用 build 为您工作的原因。

如果用户存在于内存中,rails 将足够聪明,可以在创建凭证之前先创建一个。在我看来,当您将 build 与 Fabricate 一起使用时,它会初始化用户和凭据,因此当保存用户时,它会使用新创建的用户保存凭据。

请注意,文档将此语法用于 belongs_to,而不是 has_one。看来您可能需要参考文档的回调部分来解决此问题。

于 2021-05-29T23:32:26.003 回答
0

你解决这个问题的方式肯定会奏效。我通常建议人们解决这个问题的方法是覆盖反向关系。在这种情况下,ActiveRecord 会做正确的事情。

Fabricator(:user) do
  credential { Fabricate.build(:credential, user: nil) }
end

Fabricator(:credential) do
  user { Fabricate.build(:user, credential: nil) }
end
于 2021-05-30T00:54:17.840 回答