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 нормально, но на Heroku это не получается?

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

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

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

Обновить

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

Потом я побежал rails db:migrate на этой новой локальной копии.

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

Обновление 2

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

rails db:migrate RAILS_ENV=production

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

ТЕМ НЕ МЕНИЕ

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

скриншот дб

Сбивает с толку: D

Обновление 3

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

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

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

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

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

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

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

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

2 ответа

Решение

Я исправил все свои миграции и теперь запускаю API на сервере Heroku.

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

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

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

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

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

Переход с SQLite на PostgreSQl для деплоя на героку.

У меня такая ситуация, но с использованием таблиц: посещаемости, событий и пользователей.

PG:undifiedTable ОШИБКА: отношение пользователей не существует

Я решил это:

  1. Локально запускаю rails db: 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. Таким образом, они меняют порядок, и сначала создается таблица пользователей, я снова создал базы данных и миграцию $rails db:createrails db:migrate - работает локально

  4. нажать на Heroku после совершения - мерзавец толчок мастер Heroku

  5. heroku run rails db: миграция

  6. Heroku открыт и готово - Вуаля - Finito

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

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

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

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

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

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

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

    в случае с герою вот хорошая статья

  2. Примените это в местной среде с

    psql <db_name> < <dump_file>

  3. Попробуй запустить миграцию

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

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

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

Другие вопросы по тегам