Порядок и взаимосвязи файлов миграции БД Heroku Rails

У меня есть 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 и перенастроить свою базу данных в соответствии с документацией, используя следующую команду heroku run rails db:migrate(используя Rails 5).

Я получаю ошибку от 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 fine, но на Heroku это не удается?

Разница между Sqlite3 и Postgresql, возможно?

Как решить эту проблему развертывания?

Можно ли просто переименовать файл миграции create_role, чтобы он имел более раннюю метку времени, чем файл миграции create_user? Это вообще рекомендуемая практика ? :Д

Обновить

Я сделал git клон моего репозитория в папку рабочего стола на моем iMac.

Затем я запустил rails db:migrateновую локальную копию.

Никакой ошибки. Все миграции БД выполнены, все таблицы находятся на месте вместе со всеми связями. Что-то действительно испортилось на конце Heroku.

Обновление 2

Сделал еще один извлечение моего репозитория в новую папку рабочего стола, запустилbundle install, а затем попробовал эту версию команды db:migrate:

rails db:migrate RAILS_ENV=production

и я вижу, что такой же вывод ошибок о ролях не существует

ОДНАКО

Затем я создал бренд порка новый проект 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внешний ключ, несмотря на отсутствие таблицы с именемrole, существующей в моей рабочей базе данных:

скриншот db

Недоумение: D

Обновление 3

Возможно, это разница между базой данных sqlite3 и базой данных postgresql.

По умолчанию приложение rails config/database.ymlуказывает, что вызывается рабочая база db/production.sqlite3данных, т. е. она не использует базу данных PostgreSQL, поэтому оно не выдает ошибку о несуществующих ролях.

И согласно этому сообщению Stackoverflow: поддерживает ли SQLite ссылочную целостность?

Похоже, SQLite3 не гарантирует ссылочную целостность 🙁

Сильная боль в заднице.

Хорошо, что это только личный учебный проект, а не рабочий проект.

Это также не реально начать с PostgreSQL, вы не можете просто отбросить и воссоздать базу данных так же легко, как вы можете с sqlite3 и Rails CLI.

Я думаю, что урок, который нужно усвоить здесь, заключается в том, чтобы сначала подумать и создать зависимые таблицы.

2 ответа

  1. Можно ли просто переименовать файл миграции create_role, чтобы он имел более раннюю метку времени, чем файл миграции create_user? Это вообще рекомендуемая практика ? :Д

    Да, это нормально для вашего случая.

    Но имейте в виду, что это нормально на шагах, когда вы строите свою систему на самом старте. Если у вас есть рабочая база данных, перед развертыванием убедитесь, что миграции выполняются успешно.

    Так что просто совет для будущего, здесь моя собственная лучшая практика развертывания производства

    1. Дамп производственной базы данных. Вы можете сделать это с

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

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

      в случае heroku здесь хорошая статья

    2. Примените его в локальной среде с

      psql <db_name> < <dump_file>

    3. Попробуйте выполнить миграцию

    4. Если все идет не так, перейти к шагу 5 еще Шаг 6

    5. Исправить проблемы миграции перейдите к шагу 4

    6. Проверьте, не повредил ли миграция данные, и если это попытка исправить миграцию и начать с шага 2, в противном случае просто разверните код 😉

  2. Я исправил все мои миграции и получил API, работающий на сервере Heroku сейчас.

    Реальный ответ: разверните к Heroku раньше, не ждите пока после заканчивать развитие на локальной машине после этого разверните.

    Развертывание на ранней стадии позволит выявить проблемы на ранней стадии, такие как расхождения в миграции между SQlite и PostgreSQL.

    Кроме того, при выполнении ссылок в файле миграции , если не используется совпадающая модель и имена таблиц, например authorvsuser, измените файл миграции для использования 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
    

    Нашел новые знания по этой ссылке:

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