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 ОШИБКА: отношение пользователей не существует
Я решил это:
Локально запускаю rails db: drop - для локального удаления баз данных
- У меня было 3 примера файла миграции
- 2019_11_07_205648_create_attendace
- 2019_11_07_215648_create_events
- 2019_11_07_225648_create_users
Я меняю день в дате в первых двух файлах на:
- 2019_11_07_225648_create_users
- 2019_11_07_235648_create_events
- 2019_11_07_245648_create_attendace
Таким образом, они меняют порядок, и сначала создается таблица пользователей, я снова создал базы данных и миграцию $rails db:createrails db:migrate - работает локально
нажать на Heroku после совершения - мерзавец толчок мастер Heroku
heroku run rails db: миграция
Heroku открыт и готово - Вуаля - Finito
Должен ли я просто переименовать мой файл миграции create_role, чтобы иметь более раннюю временную метку, чем файл миграции create_user? Это даже рекомендуемая практика?:D
Да, это нормально для вашего случая.
НО имейте в виду, что делать это нормально на шагах, когда вы строите свою систему с самого начала. Получив производственную базу данных, вы должны быть уверены, что ваши миграции успешно выполнены перед развертыванием.
Так что просто совет на будущее, вот мой собственный лучший опыт развертывания производства
Дамп вашей производственной базы данных. Вы можете сделать это с
pg_dump <db_name> > <dump_file>; scp <server>:<path_to_dump_file> ./
или https://github.com/sgruhier/capistrano-db-tasks
в случае с герою вот хорошая статья
Примените это в местной среде с
psql <db_name> < <dump_file>
Попробуй запустить миграцию
Если все идет не так, перейдите к шагу 5, а затем к шагу 6
Исправьте проблемы с миграцией, перейдите к шагу 4
Проверьте, не переносят ли данные миграцию, и попытайтесь ли исправить миграцию и начните с шага 2, в противном случае просто разверните свой код;)