首页 > 解决方案 > Rails 连接表名与迁移或模式不匹配(PG::UndefinedTable: ERROR: 关系不存在)

问题描述

在我的带有 Postgres 数据库的 Rails 项目中,我有一个用户和工作区模型。它们通过多对多关系 ( users_workspaces) 关联。如果我打开我的 rails 控制台并尝试使用 获取所有用户工作区UserWorkspace.all,我会收到以下“关系不存在”错误:

2.5.1 :001 > UserWorkspace.all
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR:  relation "user_workspaces" does not exist)
LINE 1: SELECT  "user_workspaces".* FROM "user_workspaces" LIMIT $1
                                         ^
: SELECT  "user_workspaces".* FROM "user_workspaces" LIMIT $1
2.5.1 :002 >

我不明白为什么它在寻找user_workspacesuser单数)而不是users_workspaces(两个名字都是复数)。我将查看我的代码库,看看这是否实际上设置为user_workspaces,但找不到它。我也跑过rails db:drop db:create db:migrate,但还是没有运气。这是相关文件,但我不确定问题出在哪里。

用户模型

class User < ApplicationRecord
  has_secure_password

  has_and_belongs_to_many :workspaces

  validates_presence_of :username, :email, :password, :subscription_plan
  validates_uniqueness_of :username, :email
  validates_length_of :username, :within => 3..40
  validates_length_of :password, :within => 8..100
end

工作区模型

class Workspace < ApplicationRecord
  has_and_belongs_to_many :users

  validates_presence_of :name
  validates_presence_of :admin_id
end

user_workspace 模型

class UserWorkspace < ApplicationRecord
  belongs_to :user
  belongs_to :workspace

  validates_presence_of :user, :workspace
end

架构.rb

ActiveRecord::Schema.define(version: 2018_07_28_040836) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "users", force: :cascade do |t|
    t.string "username", null: false
    t.string "email", null: false
    t.string "first_name"
    t.string "last_name"
    t.string "password_digest"
    t.integer "subscription_plan", default: 0, null: false
    t.integer "current_workspace"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["username"], name: "index_users_on_username", unique: true
  end

  create_table "users_workspaces", id: false, force: :cascade do |t|
    t.bigint "user_id", null: false
    t.bigint "workspace_id", null: false
    t.index ["user_id", "workspace_id"], name: "index_users_workspaces_on_user_id_and_workspace_id"
    t.index ["workspace_id", "user_id"], name: "index_users_workspaces_on_workspace_id_and_user_id"
  end

  create_table "workspaces", force: :cascade do |t|
    t.string "name", null: false
    t.text "description"
    t.integer "admin_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end

用户迁移

class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :username, null: false, index: {unique: true}
      t.string :email, null: false, unique: true
      t.string :first_name
      t.string :last_name
      t.string :password_digest
      t.integer :subscription_plan, null: false, default: 0
      t.integer :current_workspace

      t.timestamps
    end
  end
end

工作区迁移

class CreateWorkspaces < ActiveRecord::Migration[5.2]
  def change
    create_table :workspaces do |t|
      t.string :name, null: false
      t.text :description
      t.integer :admin_id

      t.timestamps
    end
  end
end

users_workspaces (join table) 迁移文件

class CreateJoinTableUsersWorkspaces < ActiveRecord::Migration[5.2]
  def change
    create_join_table :users, :workspaces do |t|
      t.index [:user_id, :workspace_id]
      t.index [:workspace_id, :user_id]
    end
  end
end

任何和所有的帮助将不胜感激。谢谢!

标签: ruby-on-rails

解决方案


schema.rb表中所述,由名称创建users_workspaces,您的类名为UserWorkspaces.

默认情况下,rails 尝试通过类名推断模型的表名。

因此,如果 classname 是,UserWorkspace那么其对应的 table_name 将是user_workspaces而不是users_workspaces

现在,您有两个选择,要么重命名模型,要么以某种方式在模型中提及要用于此模型的表。

选项 1 重命名模型

class UsersWorkspace < ApplicationRecord
  belongs_to :user
  belongs_to :workspace

  validates_presence_of :user, :workspace
end

Option-2 允许UserWorkspace模型指向users_workspaces表格

class UserWorkspace < ApplicationRecord
  self.table_name = 'users_workspaces'
  belongs_to :user
  belongs_to :workspace

  validates_presence_of :user, :workspace
end

更新

除了上面的UserWorkspace/UsersWorkspace模型你不需要

validates_presence_of :user, :workspace

由于您使用的是 rails 5.2,因此,rails 本身会添加presence验证以及belongs_to关联,除非您有传递optional: true参数或者您已通过以下方式声明它application.rb

Rails.application.config.active_record.belongs_to_required_by_default = false


推荐阅读