Rails 仅在有效时保存 belongs_to 关联

Rails saving belongs_to association only if valid

我们有一个设计用户模型,我们需要在注册时创建并与组织关联。

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable

  acts_as_tenant(:tenant)
  acts_as_paranoid
  belongs_to :organization, :autosave => true

  before_validation :create_organization

  def create_organization
      org = Organization.new(name: self.email)
      org.uuid = UUIDTools::UUID.random_create.to_s
      if org.save
        self.organization_id = org.uuid
      end
  end
end

我们遇到的问题是,如果用户表单出现问题(密码不匹配等),我们将留下一个孤立的组织。另一方面,如果我们将创建组织代码包装在

Warden::Manager.after_authentication do |user,auth,opts|
   make org
end

然后组织必须存在错误被放置在错误数组中并打印到屏幕上,我们也不希望出现这种情况,因为用户实际上不需要了解幕后的组织。

如何设置组织关联,以便用户变得有效但在您知道其他所有内容也有效之前不保存用户组织关联?

create替换为build,并且在父记录有效之前不保留记录。 has_one :foo 协会为您定义了一个 build_foo 方法,这是您应该用来建立您的组织的方法。它会自动将组织放在 user.organization 中,你不应该在使用 ActiveRecord 对象时手动处理外键:

  before_validation :build_default_organization

  def build_default_organization
    build_organization(name: email, uuid: UUIDTools::UUID.random_create.to_s)
  end

Rails 会自动为您保存此记录, 包含保存父 User 记录的交易中,它会自动设置所有外键都正确。

另一种选择是在创建用户时使用 accepts_nested_attributes 并通过 organization_attributes

class User < ApplicationRecord
  belongs_to :organization, :autosave => true

  accepts_nested_attributes_for :organization
end

User.create!(
  email: 'test_user@test.com',
  organization_attributes: {
    name: 'test_user@test.com',
    uuid: UUIDTools::UUID.random_create.to_s
  )
)