【问题标题】:Rails - self joins with postgresqlRails - 使用 postgresql 进行自我连接
【发布时间】:2016-09-18 21:36:21
【问题描述】:

我有一个叫做section的自连接模型:

class Section < ApplicationRecord
    belongs_to :offer
    # Self joins:
    has_many :child_sections, class_name: "Section", foreign_key: "parent_section_id"
    belongs_to :parent_section, class_name: "Section", optional: true
end

带有迁移文件:

class CreateSections < ActiveRecord::Migration[5.0]
  def change
    create_table :sections do |t|
      t.string :name
      t.references :offer, foreign_key: true

      t.references :parent_section, foreign_key: true
      t.timestamps
    end
  end
end

使用 mySql 很好,但后来我删除了数据库,将它们更改为 postresql(因此它们对 heroku 友好),并创建了新数据库。尝试rails db:migrate 后出现错误提示:

StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "parent_sections" does not exist

可能发生了什么? mysql和postgresql中的self join有区别吗?

【问题讨论】:

    标签: ruby-on-rails postgresql heroku rails-activerecord


    【解决方案1】:

    您的t.references 电话:

    t.references :parent_section, foreign_key: true
    

    将尝试用 PostgreSQL 做两件事:

    1. 添加一个名为parent_section_id 的整数列。
    2. 在数据库中添加foreign key constraint 以确保引用完整性(即确保parent_section_id 中的值引用部分存在)。

    您的问题在于 2。对于t.references :parent_section,FK 看起来像:

    parent_section_id integer references parent_sections(id)
    

    因为它使用标准的 Rails 命名约定,这就是您的 parent_sections 错误的来源。您可以为 FK 约束指定目标表,就像您可以将 :class_name 提供给 belongs_to 一样:

    t.references :parent_section, :foreign_key => { :to_table => :sections }
    

    此修复会触发您的下一个问题:您无法为不存在的表创建 FK,并且在您的 create_table :sections 块执行完成之前sections 将不存在。

    这个问题有两种常见的解决方案:

    1. 创建包含所有列的表,然后添加 FK 约束。在你的迁移中是这样的:

      create_table :sections do |t|
        t.string :name
        t.references :offer, foreign_key: true
        t.references :parent_section
        t.timestamps
      end
      add_foreign_key :sections, :sections, :column => :parent_section_id
      
    2. 创建没有引用列 (parent_section_id) 的表,然后在后面添加引用列和 FK。在你的迁移中是这样的:

      create_table :sections do |t|
        t.string :name
        t.references :offer, foreign_key: true
        t.timestamps
      end
      change_table :sections do |t|
        t.references :parent_section, :foreign_key => { :to_table => :sections }
      end
      

    【讨论】:

    • 多么棒的答案!我一回到家就试试这个。我要补充的是,执行 db:reset 后错误消失了,但之后我仍然无法进行迁移。
    • @Ancinek 确保接受答案,如果这对你有用 - 这是一个很好的做法,也是一个很好的做法,所以接受解决了你的问题的答案。通过这样做,您既可以奖励为您提供解决方案的用户,也可以让社区知道问题已解决。
    猜你喜欢
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 2013-07-21
    • 2023-04-06
    相关资源
    最近更新 更多