Many people talking about db migrations, especially about its rollback possibility.
I doubt, whether it is useful at all, because schema of db and model are tightly connected with application logic (MVC).
Suppose i've done rollback of some migration. And what ? The application will not work, because its logic fully relies on db.
What are the use cases of rollback ability for db migrations ?
Update 1
The main question
Why the rollback is presented as a feature, when i need to change the code ?
I don't create the migrations, like "add_another_field_to_table". Instead, each migration file fully describes each table in DB. When i need to change something in my DB, i just change the migration file, but don't roll it back.
Really, if i rollback the migration, it does't brings me back in time, like a version control does. I have a lot of work, when changes are planned and rollback gives me nothing.
The point of rollback is that you rollback code and DB at the same time. The scenario is you upgrade your code and your DB on your production server, then you find a bug and you really need to go back. So rollback your code and use your down migration to roll back your DB.
What are the point of Up migrations?
You create table structures.
You code round it, it works well.
You put site into production, everyone is happy.
Oh, wait, they want a new feature that involves adding a column to an existing table.
How do you handle this? You have to add a column to your development tables, test code, update live site without forgetting to update live DB at the same time (cos if you do there will be big errors) And also remmember to preserve existing live data. This aspect of DB management can be a real pain without a nice managed solution like rails has.
So ...
Code a one line migration that adds a column
Run migration on dev copy, scehma.rb will update
Code new features, if you need to check DB schema use schema.rb NOT migration files.
Now your ready to release on production ....
Update code on production
Run migrations on production. Rails will automatically work out what needs to be applied and do it for you!
Sure, with you adding one column it's not that confusing to do it yourself.
But what if there were 3 programmers all adding migrations? What if you have many live sites, all at different versions? Is that live site 2 or 17 migrations behind? What do I have to do to get the DB up to the latest code, whilst preserving live data? Can you see how this would very quickly get confusing to deal with?
Rails migrations (and practically every migration system works on the same principles) are designed to make updating DB structures really easy. Well worth using properly.
I've found that rollbacks are only useful if they are done locally, ie while you're working on a new bit of code. Once a migration has been committed into your version control system, if you realise there was a mistake then it doesn't really work to roll back the migration because other developers will have pulled the migration down and run it, so you'd need to tell them to roll back as well - this is too difficult to manage and also makes you look incompetent :)
Better in this situation to just do another migration to fix the problem, then everyone (including your production server) just sticks with the pull & migrate system.
Don't really understand your problem, but i try to explain a bit the rollback.
You do rollback if you want to undo the changes by the respective migration. This means that the database will be modified, and also your schema.rb will be automatically regenerated. When you do this probably you want to remove the referencing code too. For example if you removed a field from the model, probably you don't want to refer to that attribute in your code. If you try to access then will gives you undefined attribute exception. That's it.
Can become a bit cumbersome to rollback for example if you created some model 10 migrations before, and you want to change some fields. It's better to create a new migration and modify there, instead of rolling back to the respective migration.
Update 1
Read your update, and i think yo don't use the main advantage of migrations, the flexibility.
But your solution gives more overview of the database situation. If you like to do that way, I suggest the following steps in order.
Roll back to the respective migration.(rake db:migrate VERSION=XXX, I like better rake db:rollback STEP = 2 for example, rolls back 2 migrations, STEP optional)
Make your changes
Migrate your database to update all the tables, and get to current migration version.(rake db:migrate)
This feature don't affect your models or something, just changes the migration file, regenerates your schema.rb and changes the database structure, nothing else. Can't do code rollback like with version control system, and don't really has sense to do something like that. You have to take care about not using removed fields. Rails has automated mapping between database fields and model attibutes, for example if you have an user_id in your comment table, you can call it as an attribute in your model, comment_instance.user_id.
Consider a scenario where you use capistrano to deploy your site and create timestamped snapshots of each deployment. Using the timestamp on the folder and your migrations, you could identify which versions of the code and schema go hand in hand and perform a rollback.
A git repository would give you similar options.
Of course, the real problem is that once users of a site start adding data, that will potentially get purged too, unless you back it up before a rollback and painstakingly restore it at a later date.
I use migration rollback locally with rake db:migrate:redo while working on migration code and before final commit.
Related
I am new to programming. I am using Rails 4 and Postgres as database in production. When I change my database structure, what is the best practice to update production database when deploying using Capistrano? I want to keep all the data in production intact.
I noticed sometimes when I changed schema and deploy to production, some of the existing data records are lost.
Normally when making alterations to your schema you'll use rails g migration to produce new migrations and then do things like this:
class AddUsersDiscountToken < ActiveRecord::Migration
def change
add_column :users, :discount_token, :string
end
end
This migration will add a discount_token column to the users table and can be applied with:
rake db:migrate
Within Capistrano there's a task that will do this for you once the deploy is successful. No data should be lost, no records altered apart from introducing this new field. If anything else happens you've got something very odd going on in your migrations.
Remember, a few rules:
Always back-up your data before applying any migrations using the proper tool. mysqldump is a good place to start. Copying the binary MySQL data files is not adequate and will not work reliably, if at all.
Always test your back-ups and ensure everything is there. The backup process may have terminated early for some reason and failed to properly back up all the tables and data.
Never deploy migrations on your live production database without testing on a copy first. This is where the backup comes in handy, you get a chance to restore it, run the migrations, and test the results.
This is why having a staging server is often handy, even if it's just a temporary one, or not as powerful as your production server. It allows you to test your migrations on actual, production data without running the risk of interrupting service. Run your new production code with your newly migrated production database and verify that the new features you've added are functioning correctly and also check you haven't broken any old code with regressions.
Remember, migrations that alter the schema of large tables, such as those with millions of rows, may take some time to complete, especially on servers with non-SSD backed databases. When testing on your staging system make a note of how long it takes to complete as you may need to give your users advance notice for scheduled maintenance or make alterations to your plans to be less disruptive in terms of migrations.
Unless you are deleting a table or removing a column migrations will never cause you any issues.
To avoid some migration-related issues make sure you are following this:
If possible try to rename the table or column than deleting and creating a table with identical structure.
Check if your migration is reversible in case you need to rollback
If you are writing a script to update the database make sure you have counter-script ready.
Most important understand what the migration is exactly doing cross verify it on staging environment to make sure you are not loosing your data - By #CraigRinger
Perhaps a stupid question, and without code, so I'm not sure I'm on the right StackExchange site. If so, sorry and give me a comment please.
I begin programming in Sinatra (only intranet until now) and in the samples they almost always use migration with activerecord, the same with RoR.
I have experience enough with activerecord itself and it is very helpfull but I'm not sure why migration is always used ? If I create a project I just create a SQL script or a Ruby activerecord script that does the creation of the DB for me and that's it..
If I need the site or script somewhere else I just need to execute that script and ready.
Obviously I'm missing here a lot, so who can me explain the other benefits or point me to a good explanation ?
From Rails docs:
Migrations are a convenient way to alter your database schema over
time in a consistent and easy way. They use a Ruby DSL so that you
don't have to write SQL by hand, allowing your schema and changes to
be database independent.
So, the main two benefits are:
It's like Git for db schema, you won't know how that's useful until you are in a mid-size or big project with many contributors and someone makes a bobo :)
You write ruby code to build your db schema, this way if you decide to move from mysql to pg for example, you don't need to open up pg manual and check code compatibility
Update
In the api docs of migrations, you will find many nice use cases (to be honest i didn't know about half of them) ... check it out (http://api.rubyonrails.org/classes/ActiveRecord/Migration.html)
Building a creation script for your database is great, provided two things:
All your database deployments are on new machines
You get your database schema exactly right the first time
In our modern agile environment we not only don't believe it is possible for a project larger than a few lines of code, we also don't encourage aspiring to it.
Active Record's Migrations offer a way to describe your database incrementally. Each "migration" defines how to add its features to the database ("upgrade"), and how to remove them if necessary ("downgrade").
When running migrations, on top of actually running the scripts, Active Record also maintains its own table (schema_migrations), to remember which migrations have been applied to the database, and which are pending.
This enables you to build your database alongside the features as you develop them. It also facilitates working in teams, since each team member develops her own migrations, and Active Record "stitches" everything together, so you don't have to maintain a monolithic creation script.
So after alot of reading i found out that i dont need to plan my database ahead. I just start working on the application and do migrations on every change.
So for example if I decide to add something I add it via migration. Then on another migration I delete it for some reason. And in the end I decide to get it back. After a short time there will be a mess of migrations.
How do I keep track of them? Wouldnt be easier to think of the database structure in the first place?
Rails way is to do everything via migrations. As per your scenario it would be like:
migration1 #add column A
migration2 #remove column A
migration3 #add column A again
It seems like there are lots of migrations, but in practical scenario it will keep your database changes clean. Because at any given time when you do:
rake db:migrate
Rails will run only the pending migrations.
And at any given time you will see the db/schema.rb file with all the migrates and latest migration number as the version.
Having said that, if you want to revert a migration there are commands like rollback commands. Read more about migrations here.
You can see your database structure inside db/schema.rb which will show you all the tables, columns and indexes currently in your app.
Not as helpful if you're constantly changing a column, but you can also run rake db:migrate:status which will output a list of all migrations, and tell you whether they've been run or not.
I have an existing database in which I am converting a formerly 'NULL' column to one that has a default value (and populating that with said default value). However, that value is an ID of a record I need to create. If I put this record in db/seeds.rb, it won't run because db/seeds.rb runs after migrations -- but the migration needs seed data. If I leave the record creation in the migration, then I don't get the record if I make a fresh database with db:load. Is there a better way other than duplicating this in both db/seeds.rb and the migration?
Thanks!
While I can understand your desire to stay DRY and not have to write this in both the migration and seeds.rb, I think you should write it in both places. Not just to make it work, but to accomplish different requirements related to your problem.
You need to ensure that your migration can execute properly regardless of external processes. That means you should put any code required within that specific migration. This isn't to accomplish anything besides making sure your migration executes properly. Suppose someone else tries to migrate without knowing you put part of the code in seeds.rb, it would be very difficult for them to figure out what's going on.
You can make db:load work properly by including similar code in seeds.rb. However, you should be evaluating the current state of your database in seeds.rb due to the fact that it runs after the migrations. So you can check to see if the column exists, and what the default value is etc. This means that if the migration ran and took care of everything, seeds.rb doesn't repeat work or modify values inappropriately. However, if the migration did not set these variables as expected, it is able to set the values.
I'd recommend looking at it as two separate issues so you can be more confident of each one executing successfully independent of one another. It also creates better maintainability for understanding by yourself or others of what's happening in the future.
In my opinion you should treat this in both db/seeds.rb and the migration.
The migration is used to get an existing database from an older version to another version while seeds.rb and schema.rb are used for a fresh database with the latest version.
I'm switching to RoR from ASP.NET MVC. Yeah, migrations are cool, but I do not need to use different databases in my web applications. Postgresql will do just fine.
So is it okay if I use PGAdmin to create and administer my databases and schema and avoid all these fancy migrate, rake etc?
Update
Thanks everyone! Now I better understand what migrations are, and why I should use them.
I don't think that's what migration means.
Migrations in rails (and in other frameworks) is a method by which you can use to update your database schema when there are multiple versions of the same database running
For example, you may have two databases, one running on your production server, and another running locally for development. After a few days of coding, your local development database may looks a bit different. With migrations, you can simply push your code to the production server and then run the migrations to automatically update your production database so it is up-to-date with the one you use locally for development.
So, to answer your question, Yes it is OK but you might not get a few of the migrations niceties when the time comes that you'll have to maintain multiple versions of your database.
Have to agree with charkit but one (rather two) important note why you should use migrations: Migrations don't make up the model definitions. They are stored seperately in a file schema.rb. This defines the rows and tables of your database. When looking into the file, you find these lines:
This file is auto-generated from the current state of the database. Instead of editing this file, please use the migrations feature of Active Record to incrementally modify your database, and then regenerate this schema definition.
The second reason is for testing: you can easily set up a test database to run all your tests against without the need to touch the "real" database. I know when developing, this is not a big problem but this will get more important after some time.
So, yes, it is possible to use PGAdmin to create all your database related stuff but you should not forget to always keep the schema file up to date and come up with a solution for testing.
With migrations you're able to develop your database schema in Ruby and this is usually database indpendent.
In short, spend the 20 minutes or so to really get migrations and the value they add. Then determine whether or not you want to ditch them. Strangely for me I learned Rails before I started my first MVC project; one of the things I missed most was migrations.
From a technical standpoint you should be fine without them.