I ran a simple rails migration on a large MySql2 db to add a column to a table:
class AddMiddleNameToPerson < ActiveRecord::Migration[5.0]
def change
add_column :person, :middle_name, :string
end
end
I was disconnected from the server running the rails app during the migration. I then reconnected and checked the migration status with bundle exec rake db:migrate:status, which showed it as down:
down 20170424182410 Add middle name to person
I assume it was still running in the background. So I left it for some time, and eventually using the rails console I verified that person.middle_name was accessible on objects. However, db:migrate:status still shows the migration as down, and if I try to run db:migrate again I get an error:
Mysql2::Error: Duplicate column name 'middle_name'
So it seems that the new column is in the database, and accessible through ActiveRecord, but rake db:migrate:status finds the migration as down and rake db:migrate attempts to re-run it, unsuccessfully.
If this is a production database (or other database with important data) then do not rake db:reset as that will drop the database and you'll lose everything; also don't db:migrate:down as that will drop the middle_name column and you'll lose whatever middle names you already have.
First get a backup of the database or at least the table you're working with.
Second, connect to the database with the mysql CLI tool and say describe people;. The information in your question suggests that you will see the middle_name column in there but it doesn't hurt to make sure you're connecting to the right database. If middle_name isn't there then you're almost certainly connecting to the wrong database somewhere, if it is there then you just have a migration issue to clean up.
You say that the database connection was dropped before the migration finished. Migrations work in this sequence:
Run the migration to update the database.
Record the migration's version number in the schema_migrations table.
Regenerate db/schema.rb or db/structure.sql.
If 1 completes but the connection is lost then 2 never happens so the migration will have run but Rails won't know it.
If no other environments need the migration then you can simply delete the migration and rake db:schema:dump or rake db:structure:dump to get a fresh schema.rb or structure.sql. Migrations are just temporary bits of code to get you from A to B so deleting them after they've been run everywhere is fine (and even recommended), all that matters long term is your database's structure (which is in db/schema.rb or db/structure.sql).
If other environments need to run the migration then you can manually patch the schema_migrations table; connect to the database with the mysql CLI tool and say insert into schema_migrations (version) values ('20170424182410');. Rails will now know that the migration was run and future rake db:migrate calls will be happy. Then you'd want to refresh your schema.rb (with rake db:schema:dump) or structure.sql (with rake db:structure:dump).
You probably have a db/schema.rb file for tracking your database's structure (including the version numbers of the migrations that have been run). If you do then you'd use rake db:schema:dump to regenerate it. If you have db/structure.sql then you'd use rake db:structure:dump.
Related
im trying to update my Bitnami Redmine database, by using rake db:migrate RAILS_ENV=production but the problem is that the status says that i have many updates to do, but when i try theses updates i allways receive a message that the column or the table already exists, there is some command to "jump" db to especific version?
You can always "inject" a version into the schema_migrations table to trick the migration system into ignoring them, but TBH I'd be looking into why the migrations are so out of whack.
Worst case, you could always add column_exists? checks to each failing migration, and not add or update a column if it already has been added. But again, you run the risk of your migrations being out of spec with the state of the actual database.
I have two docker containers for mysql and ruby and the ruby container is dependent on mysql container.
In my docker-compose, I have volume-mounted an sql dump to the mysql container's /docker-entrypoint-initdb.d so that it gets executed upon starting the container for the first time and the database gets populated with some data.
The sql dump gets executed and the data gets restored to the db container as expected, but the problem is, while starting the ruby (with rails) container, it throws out a migration pending error. I understand that this is happening because there is no any schema migration versions recorded in the schema_migrations table as the data was deliberately restored from the sql dump.
But, even running docker-compose run <container> rake db:migrate wouldn't help because it throws out a table already exists error as the tables have already been created.
How do I sync the rails schema migration versions with the actual data in the database?
I've also tried by manually adding the latest schema version number to the schema_migrations table but still returns migration pending error. And, I cannot run docker-compose run <container> rake db:create db:migrate before restoring from sql dump because the files inside the container's /docker-entrypoint-initdb.d will only be executed if the database isn't created yet.
I think you can dump all data inside schema_migrations along with your initial dump schema, so that it will contain the migration versions and it won't raise an exception upon running rails db:migrate.
Update:
The older version of rails actually checks all schema versions to decide whether it needs migration or not. You can check here for more info.
def needs_migration?(connection = Base.connection)
(migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
end
Hope this will help.
You can write bundle exec rake db:migrate inside your docker_entrypoint file.
I can't for the life of me figure out what's going on here, im not SUPER familiar with rails however:
I've modified my database.yml file to point to a new mysql test database instead of sqlite. When doing a RAILS_ENV=test db:drop db:create db:seed on dev it works fine.
HOWEVER it always fails on test, citing a table doesn't exist when being altered by one of the migrations. I tried the exact same .sql file loaded up on the database for dev as on the test db with no errors.
I was able to delete the test db and duplicate the dev database and it would work fine, but for some reason...with migrations it will not work on the test database (which is a freshly created database, but so is the dev technically since I drop and recreate it from scratch with a seed file everytime)
What could cause such a thing? Migrations working fine on a fresh DEV database (Mysql2) and not on a fresh TEST database (Also Mysql2)
for specifics the error is complaining about a table not being able to be altered, because it doesn't exist. (I confirm in SQL Pro that the table doesn't exist as well), but when migrations run on Dev database it works fine (even after being deleted and commands above (but just ran in RAILS_ENV=development) ran.
When you run db:create all it does is create a completely empty database, with no tables... you need to run either db:migrate or db:test:prepare in order for the actual tables (empty of data) to be added to the test database.
So your usual run should be: db:drop db:create db:migrate db:seed
HOWEVER... db:seed isn't going to work the way you want it to... every test completely empties the database of data every time (this is to prevent cross-contamination of test data), and db:seed is to add data to your development environment.
In the test environment you need to duplicate any seed-data into fixtures instead (or use appropriate factories).
I am still new to rails and I have some questions regarding rails migration.
I am using rails 5, windows 8. I generated a model and wrote some code which creates a table with columns. Then I deleted that table from my development db (MySQL) and tried to execute db:migrate again to see if it would create the table and columns written in the migration file. After executing db:migrate, it didn't show any messages in the terminal and it did not create the table and the columns.
Based from my observation, deleting the version of my migration file from schema_migrations and running db:migrate once again, it worked and created the table and columns.
I would like to ask the pros of rails development on why is this happening and what should I do when I start to develop a large database model.
I would also like some suggestions about great resource materials for learning ruby on rails.
Thanks!
Its because rake db:migrate is running only migrations for the current env that have not run yet. So if you run db:migrate and then manually delete table form DB, your app does not know that.
MIgration Guides
I have created an app using a badly named database, all alterations to important data in the database have been done in fixtures so that I can just drop the database, recreate it and then rake migrate the database tables and fill them with the initial data from the fixtures.
I would like to change the name of my database now, so I updated the database.yml file to reflect another database name. I created the database in mysql and then tried to run the migration and fixtures.
Running the migration with trace shows that it is running commands to create tables etc. However once I am finished I get errors in my application saying that the tables don't exist in the new database.
I go into mysql and check the database and it is completely empty. I have tried wiping everything and running the migrations a few times but nothing changes. Is there something I am missing?
I don't know what commands you used to do the migration, but to migrate a production database (which I infer from the tag, "production-environment"), you have to do:
RAILS_ENV=production rake db:migrate
If that's not the answer, then please provide the command you used to perform the migration, which database you expected to be affected, and the relevant bits of database.yml.