我正在尝试为一些预先存在的数据库表创建Rails模型。
有1个主表,其中有1个子表。
问题可能是每个表上“外键”的名称不同
class MainTable < ActiveRecord::Base
has_many :child_tables, :class_name => 'ChildTable', :foreign_key => "child_column_name"
accepts_nested_attributes_for :child_tables
self.primary_key = "main_table_column_name"
self.table_name = 'main_table'
end
class ChildTable < ActiveRecord::Base
belongs_to :main_table, :class_name => 'MainTable', foreign_key: "child_column_name", :primary_key => "main_table_column_name"
self.table_name = 'child_table'
self.primary_key = "child_table_column_name"
end
鉴于主表每个子表仅具有1条记录,但是每个主表可能有许多子记录-这些关联看起来正确吗?
我希望能够做类似的事情:
m = MainTable.new
m.some_value = "123"
m.mntbl_key ="999"
c = ChildTable.new
c.something = "Foo"
m.child_tables << c
m.save!
编辑:由于我更新了上面的代码,因此我不再遇到错误。现在它可以工作,但是我必须在两个表上分配ID。 如果我在主对象上分配ID,它将不自动在fk列中为子对象提供该ID 即
m = MasterTable.new
m.master_table_column_name = 99
c = ChildTable.new
m.child_tables << c
m.save!
-- This will Insert ok into Master but will INSERT a blank row into the child
但是:
m = MasterTable.new
m.master_table_column_name = 99
c = ChildTable.new
c.child_column_name = 99
m.child_tables << c
m.save!
--This works and inserts correctly into both tables
--------------------------------- OLD: 但是我得到了错误:
ActiveModel::MissingAttributeError: can't write unknown attribute `ctbl_key'
我想念什么吗?
答案 0 :(得分:1)
一对多关联仅使用一个外键列,而不是两个。
通常在Rails中这样设置:
class Parent
has_many :children
end
class Child
belongs_to :parent
end
实际关联存储在children.parent_id
列中。
所以可以说我们有一个非常规的外键:
class Parent
has_many :children, foreign_key: 'padre_id'
end
class Child
belongs_to :parent, foreign_key: 'padre_id'
end
足够容易。我们只需要告诉双方关联外键是什么。请注意,只要可以从关联名称中推断出类名,就不需要class_name
选项。
自定义主键或表名也不成问题,因为ActiveRecord在解析关联时会查看模型类的定义。
class Parent
self.primary_key = :custom_pk
has_many :children, foreign_key: 'padre_id'
end
class Child
self.table_name = 'bar'
# this will correctly reference parents.foo
belongs_to :parent, foreign_key: 'padre_id'
end
还有一个普遍的问题,您必须先保存一条记录,然后才能向其添加子项:
irb(main):024:0> m = MainTable.new
=> #<MainTable custom_pk: nil, created_at: nil, updated_at: nil>
irb(main):025:0> m.child_tables.new
=> #<ChildTable id: nil, padre_id: nil, created_at: nil, updated_at: nil>
irb(main):026:0> m.save!
(0.3ms) BEGIN
(0.4ms) ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Child tables is invalid
from (irb):26
从Rails 5 belongs_to
开始关联在默认情况下是非可选的。由于child_tables
为nil,因此padre_id
实例无效。
您要么需要先保存父记录:
irb(main):033:0> m = MainTable.create!
(0.5ms) BEGIN
MainTable Create (0.7ms) INSERT INTO "main_table" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "custom_pk" [["created_at", "2018-11-20 17:31:09.545476"], ["updated_at", "2018-11-20 17:31:09.545476"]]
(0.8ms) COMMIT
=> #<MainTable custom_pk: 5, created_at: "2018-11-20 17:31:09", updated_at: "2018-11-20 17:31:09">
irb(main):034:0> m.child_tables.new
=> #<ChildTable id: nil, padre_id: 5, created_at: nil, updated_at: nil>
irb(main):035:0> m.save
(0.3ms) BEGIN
MainTable Load (0.6ms) SELECT "main_table".* FROM "main_table" WHERE "main_table"."custom_pk" = $1 LIMIT $2 [["custom_pk", 5], ["LIMIT", 1]]
ChildTable Create (0.9ms) INSERT INTO "child_table" ("padre_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["padre_id", 5], ["created_at", "2018-11-20 17:31:21.737989"], ["updated_at", "2018-11-20 17:31:21.737989"]]
(0.6ms) COMMIT
=> true
irb(main):036:0>
或者从另一端的belongs_to关联构建:
irb(main):027:0> c = ChildTable.new
=> #<ChildTable id: nil, padre_id: nil, created_at: nil, updated_at: nil>
irb(main):028:0> c.build_main_table
=> #<MainTable custom_pk: nil, created_at: nil, updated_at: nil>
irb(main):029:0> c.save!
(0.3ms) BEGIN
MainTable Create (0.8ms) INSERT INTO "main_table" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "custom_pk" [["created_at", "2018-11-20 17:24:29.344332"], ["updated_at", "2018-11-20 17:24:29.344332"]]
ChildTable Create (1.1ms) INSERT INTO "child_table" ("padre_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["padre_id", 3], ["created_at", "2018-11-20 17:24:29.346764"], ["updated_at", "2018-11-20 17:24:29.346764"]]
(0.7ms) COMMIT
=> true
答案 1 :(得分:0)
不确定这是否是您面临的问题,但是目前您正在初始化新的MainTables和ChildTables,但是您没有保存它们。
这意味着不会为它们分配ID,这又意味着当您尝试向主表分配子表时,它没有主表(或本身)的ID以创建联接记录。
在保存子记录之前尝试保存记录