使用模型的嵌套属性而不自动递增ID

时间:2017-11-03 16:45:33

标签: ruby-on-rails postgresql ruby-on-rails-5 accepts-nested-attributes

我有以下模型及其相应的模式定义:

class Cube < ApplicationRecord
  has_many :faces, inverse_of: :cube, dependent: :destroy
  accepts_nested_attributes_for :faces
end

create_table "cubes", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end


##
# NOTE: Even though this model's related database table has an +id+ column, it
#       is not a regular auto-generated, auto-incremented ID, but rather an +id+
#       column that refers to an uuid that must be manually entered for each
#       Face that is created.
##
class Face < ApplicationRecord
  belongs_to :cube, inverse_of: :faces, optional: true
  validates :id, presence: true, uniqueness: true
end

# Note that id defaults to nil.
create_table "faces", id: :uuid, default: nil, force: :cascade do |t|
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.uuid "cube_id"
  t.index ["cube_id"], name: "index_faces_on_cube_id"
end

正如您从上面的评论中看到的那样,id模型不会自动生成Face,而是在创建时预期输入{因为我们在现实世界已经有一个唯一的标识符,我们想要使用它而不是添加另一个ID。)

当我尝试执行以下操作时出现问题

cube = Cube.new

cube.faces_attributes = [
  {
    id: "2bfc830b-fd42-43b9-a68e-b1d98e4c99e8"
  }
]

# Throws the following error
# ActiveRecord::RecordNotFound: Couldn't find Face with ID=2bfc830b-fd42-43b9-a68e-b1d98e4c99e8 for Cube with ID=

对我而言意味着,由于我们传递的是id,因此Rails希望这是对关联的Face的更新,而不是传递要创建和关联的新Face使用cube

我可以通过accepts_nested_attributes_for禁用此默认行为,还是必须为我的特定用例编写自定义代码?

1 个答案:

答案 0 :(得分:0)

您需要将模型配置为使用非标准外键。

doPost(e)

然而,在任何体面的数据库设计中,主键都是唯一的。这就是唯一标识符背后的重点!由于NULL不是唯一的,因此它也必须是NOT NULL。这应该在数据库级别强制执行。不仅仅是应用级别验证。

一个更好的解决方案,但更少的麻烦可能是坚持使用Rails约定命名外键class Face < ApplicationRecord self.primary_key = 'uuid' belongs_to :cube, inverse_of: :faces, optional: true # your validation is for the wrong column. validates :uuid, presence: true, uniqueness: true end 并将其类型更改为UUID而不是自动递增ID。这将大大减少每个模型所需的配置量。