Rails 6:新建未保存记录时能否创建用于委托的关联记录?
问题结论
你的判断不正确,Rails ActiveRecord 原生支持父对象未持久化(无ID)时预先构建关联对象,父对象和子对象会在同一个保存事务中自动完成外键赋值,不需要提前获取父对象ID。
问题原因
你当前的实现有两个问题:
- 你使用
after_create回调在父对象保存完成后才创建关联的mobile记录,导致新建父对象时mobile关联为空,委托方法调用时报空错误 - 没有处理新建
CustomerProfile实例时的关联初始化逻辑
修复方案
删除原有的after_create -> { create_mobile }回调,新增after_initialize回调用于自动初始化关联的mobile对象即可,修改后的代码如下:
class CustomerProfile < ApplicationRecord belongs_to :user, optional: true has_one :mobile, autosave: true, dependent: :destroy delegate :number, to: :mobile, prefix: :mobile delegate :number=, to: :mobile, prefix: :mobile # 新增初始化逻辑:仅新建未持久化的实例无关联mobile时自动构建 after_initialize do build_mobile if new_record? && mobile.nil? end ... end
实现效果
修改后你就可以直接在新建对象时设置手机号,保存时会自动写入两张表:
[1] pry(main)> profile = CustomerProfile.new => #<CustomerProfile:0x00007fb371201300 id: nil, first_name: nil, last_name: nil, user_id: nil, created_at: nil, updated_at: nil> [2] pry(main)> profile.mobile_number = "123" => "123" [3] pry(main)> profile.save TRANSACTION (0.1ms) BEGIN CustomerProfile Create (0.3ms) INSERT INTO "customer_profiles" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2024-xx-xx xx:xx:xx"], ["updated_at", "2024-xx-xx xx:xx:xx"]] Mobile Create (0.2ms) INSERT INTO "mobiles" ("number", "customer_profile_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["number", "123"], ["customer_profile_id", 1], ["created_at", "2024-xx-xx xx:xx:xx"], ["updated_at", "2024-xx-xx xx:xx:xx"]] TRANSACTION (0.1ms) COMMIT => true
注意事项
after_initialize 回调会在所有CustomerProfile实例初始化(包括从数据库查询的实例)时触发,代码中的new_record? && mobile.nil?判断保证了只有新建的、还没有关联mobile的实例才会自动构建关联,不会覆盖已经存在的关联数据。
内容的提问来源于stack exchange,提问作者user3574603
相关产品推荐
相关产品推荐

