Rails 4迁移 | 添加带有引用的表

16

我正在尝试在我的Rails 4项目中创建一个“协作”表,但遇到了问题。 我希望它属于单个用户,也就是协作者。

我运行了以下命令来生成模型和迁移,我也将其复制如下。

``` rails generate model Collaboration collaborator:references project:references ```
rails generate model Collaboration project:references collaborator:references accepted:boolean

迁移:

class CreateCollaborations < ActiveRecord::Migration
    def change
        create_table :collaborations do |t|
            t.references :project, index: true, foreign_key: true
            t.references :collaborator, index: true, foreign_key: true
            t.boolean :accepted

            t.timestamps null: false
        end
    end
end

模型:

class Collaboration < ActiveRecord::Base
    belongs_to :project
    belongs_to :collaborator, class_name: 'User'
end

我更新了协作模型,包括 , class_name: 'User' 如上所示。同样地,我更新了现有的 Strategy 模型,包括一个 has_many :collaborations

class Project < ActiveRecord::Base
    has_many :collaborations
end

当我运行rake db:migrate时,会报告以下错误。
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

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

我有点困惑为什么会发生这种情况。非常感谢您的帮助!谢谢。:)

编辑:

同时添加我的User模型代码。

class User < ActiveRecord::Base
    authenticates_with_sorcery!

    has_many :projects
    has_many :collaborations
end

我删除了密码、电子邮件等字段的验证,以尝试去除杂乱。


请发布您的User.rb文件(特别是关系部分)。 - MarsAtomic
越想,这件事就越奇怪...通常,如果您尝试在多个关系中使用相同的键,则会使用class_name:别名,但是您的协作仅使用一次用户。我真的认为现在应该尝试使用belongs_to:user,即使只是出于诊断目的。 我所知道的是,您正在做的事情很好,我从未在野外遇到过它。 - MarsAtomic
@MarsAtomic - 是的,我明白你的意思。我尝试构建一个小的测试项目来专注于这个问题,因为我在一个更大的项目中遇到了类似的情况。这个小问题中复制了同样的问题。 - Michael Fich
3个回答

16

您的迁移的这部分内容:

t.references :collaborator, index: true, foreign_key: true

将尝试在数据库中创建一个外键约束,以确保collaborations表的collaborator_id列的值可为NULL或包含collaborators表中某列的id。在创建该FK之前,必须存在collaborators表。

您遇到的错误是:

relation "collaborators" does not exist

这只是告诉你没有 collaborators 表格,但你正在尝试引用它。

在创建 collaborations 表格之前,您需要迁移以创建 collaborators 表格。


这也是我想的。只是为了澄清,他将user别名为collaborator,所以他需要确保他的create_users_xxxxx.rb迁移在create_collaborations_yyyyy.rb迁移之前进行。 - MarsAtomic
哦,我在项目中早先设置了一个用户表。我试图添加一个单独的迁移来将协作者引用添加到协作者表中,但是我遇到了与第一个迁移相同的错误。 - Michael Fich
@MarsAtomic - 确实没错!问题在于我试图将用户表作为“协作者”的别名来引用。但是我还在解决错误。 - Michael Fich
那么 collaborations.collaborator_id 应该是一个 users.id 值?你觉得使用 t.references :user 如何? - mu is too short
@muistooshort - 如果我无法解决这个问题,那是我可以考虑使用的东西。如果可能的话,我想先弄清楚它当前的构造方式。 - Michael Fich
据我所知,你可以采取以下方法之一(1)使用user_id作为列名(即t.references: user)、(2)不使用外键(即foreign_key: false),或者(3)手动添加数据库外键,需要一点SQL的知识。(1)是最符合Rails的方式,(2)是在你的数据库中引入损坏数据的捷径,(3)将需要将schema.rb切换为structure.sql文档似乎没有提供其他内容。我选择了(3),因为我在数据库中使用各种AR不理解的东西。 - mu is too short

8
在Rails 5中,你可以使用foreign_key: {to_table: ... }},用法如下。
create_table :messages, id: :uuid do |t|
  t.references :from_user, type: :uuid, index: true, null: false, foreign_key: {to_table: :users, on_delete: :cascade}
  t.references :to_user, type: :uuid, references: :user, index: true, null: false, foreign_key: {to_table: :users, on_delete: :cascade}
  t.text :body, null: false
  t.timestamps
end

1

抱歉迟到了,但实质上这一切都是为了方便起见,记住这就是Rails的本质。所以,每个引用都应该指向应该以复数形式存在的表(因为一个表可以容纳多个“对象”),因此,您必须将引用变成复数形式,这样Rails才会生成对单个对象的引用。简而言之,您的迁移应该更像这样:

class CreateCollaborations < ActiveRecord::Migration
  def change
    create_table :collaborations do |t|
        t.references :projects, index: true, foreign_key: true
        t.references :collaborators, index: true, foreign_key: true
        t.boolean :accepted

        t.timestamps null: false
    end
  end
end

现在,如果你遵循惯例,那么你应该对其余部分没有问题,只需记住 belong_to 是针对单个对象的,而 has_many 是针对复数对象的。
PS:我不会为列使用过去式引用,例如accepted 编程愉快

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