Rails在非主键上添加外键

3
在Rails 5.1中,我有以下关系:
class RootArea < ApplicationRecord
  has_many :common_areas
end

class CommonArea < ApplicationRecord
  belongs_to :root_area, foreign_key: 'area_id', optional: true
end

以下是它们的迁移:
create_table "root_areas", force: :cascade do |t|
  t.integer "area_id"
  t.string "localname"
  t.string "globalname"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "common_areas", force: :cascade do |t|
  t.integer "area_id"
  t.string "localname"
  t.string "globalname"
  t.integer :root_area_id
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

我的目标是将“common_areas”与“root_areas”连接起来,使用“area_id”而不仅仅是“id”,以便单个根区域条目可以拥有多个公共区域。
例如,美国(RootArea)有加利福尼亚州(CommonArea)、德克萨斯州(CommonArea)等。
我尝试使用迁移和外键来实现这一点,如下所示:
add_foreign_key :common_areas, :root_areas, primary_key: :area_id

一开始似乎效果不错,但最终失败了:

>>> RootArea.create!(area_id: 1111, 
                     localname: ’test', 
                     globalname: ’test') # OK

>>> CommonArea.create!(area_id: 9999, 
                       localname: ’test', 
                       globalname: ’test') # OK

>>> RootArea.first.common_areas << CommonArea.first # Error

=> # SQL (44.3ms)  UPDATE "common_areas" SET "root_area_id" = $1, "updated_at" = $2 WHERE "common_areas"."id" = $3  [["root_area_id", 19], ["updated_at", "2018-02-20 14:45:52.545450"], ["id", 1]]

输出结果表明Rails试图将CommonArea的属性root_area_id设置为RootArea的主键(id而不是area_id)。
例如,在上面的示例中,生成的SQL语句应该将root_area_id设置为1111,而不是19

请问你可以分享一下你的类和关系吗? - rwold
已更新。rwoldd - stratis
谢谢。所以你没有叫做“area”的类吗?看起来使用“has_many ... through”可能是实现你想要的更简单的方法。 - rwold
我不太明白为什么既有“root_areas”表又有“common_areas”表,也不知道为什么这不是HMT等。 - Dave Newton
所以,我正在尝试做以下事情:即加利福尼亚州belongs_to美国,德克萨斯州belongs_to美国等。但我还需要能够执行USA.common_areas并输出加利福尼亚州、德克萨斯州等。最好的方法是什么? - stratis
1个回答

7
今晚稍晚时候,我在Rails IRC频道中寻求了进一步的帮助,最终用户指向了我这个非常类似于我所需的post。供将来参考,这是最终解决方案:
class RootArea < ApplicationRecord
  has_many :common_areas, foreign_key: 'root_area_id', primary_key: 'area_id'
end

class CommonArea < ApplicationRecord
  belongs_to :root_area, foreign_key: 'root_area_id', primary_key: 'area_id', optional: true
end

现在我可以成功地完成。
>>  RootArea.first.common_areas << CommonArea.first

并且将root_area_id设置为正确的area_id值,而不是id


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接