Heroku Rails 数据库迁移文件顺序和关系

Heroku Rails db migration file order and relationships

我有一个 User 模型和一个 Role 模型。当我开始构建应用程序时,我首先创建 User 模型,生成的迁移文件包含对角色的引用:

class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :first_name
      t.string :last_name
      t.string :username
      t.string :email
      t.string :password
      t.string :password_digest
      t.boolean :banned
      t.references :role, foreign_key: true

      t.timestamps
    end
  end
end

然后我创建了生成此迁移文件的 Role 模型:

class CreateRoles < ActiveRecord::Migration[5.0]
  def change
    create_table :roles do |t|
      t.string :title
      t.integer :access_level

      t.timestamps
    end
  end
end

我正在尝试使用以下命令 heroku run rails db:migrate(使用 Rails 5)根据文档部署到 Heroku 并迁移我的数据库。

我从 Heroku 收到一条错误消息:

heroku run rake db:migrate
Running rake db:migrate on ⬢ gentle-headland-79177... up, run.9293 (Free)
D, [2016-12-31T08:15:33.131367 #4] DEBUG -- :    (90.7ms)  CREATE TABLE "schema_migrations" ("version" character varying PRIMARY KEY)
D, [2016-12-31T08:15:33.152682 #4] DEBUG -- :    (11.5ms)  CREATE TABLE "ar_internal_metadata" ("key" character varying PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
D, [2016-12-31T08:15:33.155373 #4] DEBUG -- :    (1.1ms)  SELECT pg_try_advisory_lock(6845940114126317925);
D, [2016-12-31T08:15:33.172106 #4] DEBUG -- :   ActiveRecord::SchemaMigration Load (1.2ms)  SELECT "schema_migrations".* FROM "schema_migrations"
I, [2016-12-31T08:15:33.178453 #4]  INFO -- : Migrating to CreateUsers (20161117083901)
D, [2016-12-31T08:15:33.181903 #4] DEBUG -- :    (0.9ms)  BEGIN
== 20161117083901 CreateUsers: migrating ======================================
-- create_table(:users)
D, [2016-12-31T08:15:33.199351 #4] DEBUG -- :    (13.4ms)  CREATE TABLE "users" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "username" character varying, "email" character varying, "password" character varying, "password_digest" character varying, "banned" boolean, "role_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL, CONSTRAINT "fk_rails_642f17018b"
FOREIGN KEY ("role_id")
  REFERENCES "roles" ("id")
)
D, [2016-12-31T08:15:33.200707 #4] DEBUG -- :    (1.0ms)  ROLLBACK
D, [2016-12-31T08:15:33.202190 #4] DEBUG -- :    (1.2ms)  SELECT pg_advisory_unlock(6845940114126317925)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "roles" does not exist
: CREATE TABLE "users" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "username" character varying, "email" character varying, "password" character varying, "password_digest" character varying, "banned" boolean, "role_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL, CONSTRAINT "fk_rails_642f17018b"
FOREIGN KEY ("role_id")
  REFERENCES "roles" ("id")
)

据我了解,Heroku 似乎希望先定义 Role,然后再定义 User

为什么在我的本地机器上,我可以 db:migrate 正常,但在 Heroku 上却失败了?

Sqlite3 和 Postgresql 之间的区别?

我该如何解决这个部署问题?

我是否只是将我的 create_role 迁移文件重命名为具有比 create_user 迁移文件更早的时间戳?这甚至是推荐的做法吗? :D

更新

我将我的存储库 git 克隆到我的 iMac 上的桌面文件夹。

然后我 运行 rails db:migrate 在那个新的本地副本上。

没有任何错误。所有数据库迁移 运行、所有 table 以及所有关系都已到位。 Heroku 端确实有些问题。

更新 2

再次将我的存储库签出到一个新的桌面文件夹中,运行 bundle install 然后尝试了这个版本的 db:migrate 命令:

rails db:migrate RAILS_ENV=production

我看到关于角色不存在的相同错误输出

然而

然后我创建了一个 b运行d 全新的 rails 项目 honey:

rails new honey

做过bundle install

然后去了:

rails generate model User name:string role:references

最后,我去了:

rails db:migrate RAILS_ENV=production

没有错误...

我显然没有生成任何 Role 模型,为什么它没有失败?

这是控制台日志:

Warlocks-iMac:bad clementwu$ cd honey/
Warlocks-iMac:honey clementwu$ ls
Gemfile      Rakefile     config       lib          test
Gemfile.lock app          config.ru    log          tmp
README.md    bin          db           public       vendor
Warlocks-iMac:honey clementwu$ rails generate model User name:string role:references
Running via Spring preloader in process 27200
Expected string default value for '--jbuilder'; got true (boolean)
      invoke  active_record
      create    db/migrate/20170101100613_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
Warlocks-iMac:honey clementwu$ rails db:migrate RAILS_ENV=production
== 20170101100613 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0018s
== 20170101100613 CreateUsers: migrated (0.0018s) =============================

Warlocks-iMac:honey clementwu$ 

数据库已创建,甚至显示 role_id 外键,尽管我的生产数据库中没有 table 调用 role

莫名其妙:D

更新 3

也许这是sqlite3数据库和postgresql数据库的区别。

默认情况下,rails 应用程序 config/database.yml 指定生产数据库称为 db/production.sqlite3,即它不使用 PostgreSQL 数据库,因此它不提供关于角色不存在的错误。

根据这个 Whosebug post:Does SQLite support referential integrity?

看来 SQLite3 没有保证运行引用完整性:(

屁股很痛。

幸好这只是个人学习项目,不是工作项目。

从 PostgreSQL 开始也不太可行,您不能像使用 SQLite3 和 Rails CLI 那样轻松地删除和重新创建数据库。

我想这里要吸取的教训是认真思考并首先创建依赖项 table。

Do I just rename my create_role migration file to have an earlier timestamp than the create_user migration file? Is that even recommended practice ? :D

是的,你的情况没问题。

但是 请记住,当您从一开始就搭建系统时,这样做是可以的。拥有生产数据库后,您应该确保迁移 运行 在部署之前成功。

所以这只是对未来的提示,这里是我自己的生产部署最佳实践

  1. 转储您的生产数据库。你可以用

    pg_dump <db_name> > <dump_file>; scp <server>:<path_to_dump_file> ./

    https://github.com/sgruhier/capistrano-db-tasks

    如果是 heroku,这里很好 article

  2. 在本地环境中应用

    psql <db_name> < <dump_file>

  3. 尝试运行迁移

  4. 如果一切出错,请转到第 5 步,否则转到第 6 步

  5. 修复迁移问题转到步骤 4

  6. 检查迁移是否不会损坏数据,如果它尝试修复迁移并从第 2 步开始,否则只需部署您的代码 ;)

我修复了所有迁移,现在在 Heroku 服务器上获得了 API 运行。

真正的答案是:尽早部署到Heroku,不要等到在本地机器上完成开发后再部署。

早点部署会早点发现问题,比如我在 SQlite 和 PostgreSQL 之间的迁移差异。

此外,在迁移文件中进行引用时,如果不使用匹配模型和 table 名称,例如author vs user,修改迁移文件以在 运行 迁移之前使用 add_foreign_key

例如:

class CreateBooks < ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.string :title
      t.boolean :adult_content
      t.references :author, foreign_key: true

      t.timestamps
    end
  end
end

需要成为:

class CreateBooks < ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.string :title
      t.boolean :adult_content
      t.references :author, index: true # this line changed

      t.timestamps
    end

    # new foreign key specifying correct table name and column
    add_foreign_key :books, :users, column: :author_id 

  end
end

从中发现新知识link:

http://sevenseacat.net/2015/02/24/add_foreign_key_gotchas.html

从 SQLite 迁移到 PostgreSQl 以依赖于 heroku。

我有这样的情况,但使用 tables:出勤率、事件和用户。

PG:undifiedTable 错误:关系用户不存在

我解决了这个问题:

  1. 本地我运行railsdb:drop-本地删除数据库

    • 我有 3 个迁移文件示例
    • 2019_11_07_205648_create_attendace
    • 2019_11_07_215648_create_events
    • 2019_11_07_225648_create_users
  2. 我将前两个文件中的日期更改为:

    • 2019_11_07_225648_create_users
    • 2019_11_07_235648_create_events
    • 2019_11_07_245648_create_attendace
  3. 所以他们改变了顺序,首先创建了用户 table,我再次创建了数据库和迁移 $rails db:create rails db:migrate - 在本地工作

  4. 提交后推送到heroku - git推送heroku master

  5. heroku 运行 rails db:migrate

  6. Heroku 打开并完成 - 瞧 - Finito