Rails - autogenerate migrations from database changes - ruby-on-rails

Is it possible to use Rails to auto-generate a migration based on changes that took place in the database outside of Rails since the last migration?
I know that running db:migrate will change the schema.rb to match what's in the database.... (at least if don't make any migrations but I do change the database in some way manually). What I'm wondering is, if there is a way as part of that same mechanism or process to have it create a migration out of those changes.
Many thanks!

I don't think this is something Rails would do or is trying to solve. Rails wants you to explicitly manage those changes through migrations so that your database is under control (and source control).
See if this gem is what you want. - https://github.com/pjhyett/auto_migrations
It might not work with Rails 3. I think since you edit your DB directly you'd have to run rake db:schema:dump to update the schema.rb file.
If you want to capture the deltas between the different db change points then see this SO answer:
How to generate Rails Migration class automatically from MYSQL database instance? , just repeat his steps along the way.

Related

Ruby on Rails: Long list of migration files, common?

Is having a long list of migration files often common when building a web application? I seem to be adding up a long list of migration files because I keep forgetting or keep thinking of adding an extra column to a 'already' migrated database table.
Having a long list of migration files is normal. It's one of the best features of rails. Think of them as layers(like an onion) that you stack on top of each other. If you add a new column or table and then you decide that you don't want it anymore you can rollback(peel away) the latest changes. As long as you have the migration files you can move back and forth easily(don't recommend moving much but you get the point). REMEMBER DO NOT DELETE migration files once they are raked unless you do a rollback. When you rollback and delete a migration file make absolutely SURE you are at the right layer(rollback point).
why? because for example when someone clones your app and runs your migration file it goes through all the migration files from beginning to end. if something in the middle is messed up or deleted you won't be able to create the database because it goes through ALL the steps. Hope it helps.
It may be bad habit, but I migrate down using rake db:migrate VERSION=0, then change the respective migration that has (for instance) the users, and finally migrate the database using rake db:migrate. That way i have less of a mess, and know exactly which migration does what to what model. It's cleaner, but I guess this technique can be used only at the beginning of the webapp.
Hope this helps.
One more point to be noted, from rails docs
If you need to create the application database on another system, you should be using db:schema:load, not running all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations you'll amass, the slower it'll run and the greater likelihood for issues).
It's strongly recommended to check this file(schema.rb) into your version control system.
IMO, if you do the migrations correctly it should have to have a long list of migrations. Because every little change you have to do via migration. As you said, proper way is to add a new migration when you need to alter a table.
So as I mentioned I believe having more and more migrations means you are doing it correct. (Because most of the time when you need alterations to to an existing table you simple cannot drop the table and re-create it).
But having said that it always a good idea to run rake db:migrate every now and then (for an isolated db) just to make sure your migrations are working as a group.

Rails - Generating migration script from model

I am learning rails, and I came across Migrations. It seems that everytime I want to edit a model, I would need to add a migration script, even though I am not yet in production.
Can you edit your model, add all your attributes you need to it, and before releasing it, have the migration script autogenerated?
Thanks!
If your using rails 3+ you might want to consider DataMapper instead of ActiveRecord. It lets you define the data model in the model instead of multiple migration files. As I understand DataMapper lets you generate migrations from changes.
This is a tried and trusted pattern often used in the wider ORM community.
I agree with the comments so far. The idea of migrations is to make it simple to fluidly adapt your data schema to fit your application as you want to add new fields. It's a simple and beautiful system.
So yes, you can (and should) use rails generate migration... as not only does this generate the proper code in many common cases, it also keeps track of which migrations have been run in different versions of the database. See http://guides.rubyonrails.org/migrations.html#creating-a-migration
A common workflow might be something like this:
create a new model, for example User with fields like first_name, last_name, user_name
this will create an associated migration, which you can run using bundle exec rake db:migrate -- your database schema will be updated
you decide you want additional information, such as birthdate, so run rails generate migration AddBirthdateToUser birthdate:date. For some simple operations like adding a column, index, etc., the full migration code will be generated; in other cases you'll need to write the migration. When done, run the migration.
If you find a problem in development, for example a field type should be float, not integer, or you forgot to add an index, you can roll back the migration (bundle exec rake db:rollback), fix the migration and re-run it.
run your tests (which will run the migrations), and when it all works for you locally, check in the files (including the migrations) and deploy to a QA or staging server, which has its own copy of the database.
run rake db:migrate on the staging server. If you're on a team and other developers have checked in migrations, their will run, too. Now your code and data schema are in sync.
repeat :-)
There's no harm whatsoever running migrations during a production deployment (I respectfully disagree with a comment above) -- you should embrace the idea that change, even changes like this (which can be incredibly difficult in other environments) are a normal part of everyday Rails life!

How do I update migrations when upgrading from a Rails 1.2.3 app?

I'm updating a Rails 1.2.3 app to 3.2.1.
I'm trying to figure out how I can update the migration structure to be compatible with the latest version of Rails, so that, ideally, you can just run rake db:migrate when setting up the app. Currently, I have solved this by just doing rake db:migrate:up VERSION=[version_number] of whatever migration I need to run. If I just run rake db:migrate, it tries to rerun all of the migrations from the beginning and it stops (since those migrations have already been run in the db dump I have).
Migrations in the app look like this 001_add_some_model.rb, 002_add_some_other_model.rb instead of 20120209182512_add_some_model.rb.
Does anyone have any experience with this? How can I fix this?
I think you should restart your migrations, drop all the migration you have and create a new migration with definitions of your current models. See this migration as a starting example.
It is not recommended to run all migrations to set up a new database even in an up-to-date Rails 3 app. This is explained in db/schema.rb:
Note that this schema.rb definition is the authoritative source for your
database schema. If you need to create the application database on another
system, you should be using db:schema:load, not running all the migrations
from scratch. The latter is a flawed and unsustainable approach (the more migrations
you'll amass, the slower it'll run and the greater likelihood for issues).
Instead of what had been suggested, I would create new migrations from scratch.
Start you all your models at the current state and create new migrations for each of them, this way you could still use the power of the migrations later, like adding a column to a table or change a column type.
If you create a singe migration for all your models, like has been suggested you'll loose the model track in migrations name.
This is just another way to do it and reflects my own vision.

Why is db:reset different from running all migrations?

In section Rails Database Migrations of Ruby on Rails Guides, there is one line saying that
The db:reset task will drop the database, recreate it and load the current
schema into it. This is not the same as running all the migrations.
Can anyone tell me where exactly they are different and why it is more error prone to replay the migration history?
I'm fairly new to Ruby on Rails. Thanks in advance.
The schema file contains the current structure of your database. When you load it, you are guaranteed to have the exact schema in your db that is in the file. Migrations were designed to make incremental changes in the database. You may add a table, then some columns, and then remove the table in three separate migrations. There's no need to go through all this when the schema already knows that the table no longer exists.
On why they are error prone, I'm not totally sure. The one thing I can think of is that migrations can be used to make changes to data and not just the structure.
Running rake db:reset will rebuild the structure of your database from schema.db, which essentially works as a cached version of your migrated database structure. Running all your migrations, on the other hand, applies the migrations one by one, which may include arbitrary code to accomodate for changes to the database (e.g. prepopulate an added counter cache column).
It can be more error prone to replay the migration history, since it is the product of changes to both the structure and data of the database. If the developers haven't been careful, it might not apply cleanly to a fresh environment (e.g. the migration assumes an old version of a model). On the other hand, schema.db can get out of sync if you edit a migration once you've migrated (a useful trick to avoid migration explosion during development). In that case, you need to run rake db:migrate:reset.

Aggregate migrations in Rails

I have several dozens Rails DB migrations which were written over a year. Is there a way to aggregate them to one migration so that I will just see a full DDL statement for the database as it exists now? I just need the current snaphot without all the history of how we got to it.
It is possible, but probably not a good idea to aggregate the migrations!
Maybe ask:
Why do you want to do this?
How often do you really need to migrate all the way to VERSION=0 and then back up again?
Is something really broken? (if not, then don't fix it)
I've had the same problem once.. I ended up just re-ordering my migrations, because changes in the schema caused it to not correctly migrate up/down anymore. I would be hesitant to do that again.
If you have migrations which just add fields or indexes, then maybe you can combine them with the main migration for the model -- but beware that you can't reproduce old situations anymore, e.g. older DB-dumps may not be compatible with what migration number they should be compatible with -- that is probably the biggest argument against aggregating...
Technically, you can dump the schema and then load it directly - that is one way:
rake db:schema:dump
then create a single new migration with the contents of the schema dump file db/schema.rb
Here are some similar questions:
Rebase Rails migrations in a long running project
Deleting/"Rebasing" rails migrations
Way to "flatten" Rails migrations?
Should I flatten Rails migrations?
P.S.: I found it useful to stick with the old migration numbering scheme, where the migrations do not use timestamps - for me this works better (is easier to see in which order they are).
e.g. in your config/application.rb file:
config.active_record.timestamped_migrations = false
You should never be using all the migrations to get a database up and running. The current schema.rb is always what the DB looks like 'presently'.
It's good practice to periodically just truncate your migrations if you have a ton of them in there. We finally did that with one of our larger applications, removing a good 50 migrations from the folder because the only thing that matters is schema.rb. Migrations are just that, a way to migrate and make changes to an existing state of the database. They should only ever have to be run once.
You can simply load the current schema into the DB.
rake db:schema:load RAILS_ENV=[production, test, etc.]
This will take the schema.rb file's version of the schema, and load it into the DB without running individual migrations.
NOTE: if you have migrations that put data into the DB (e.g. default values, for example), that data will not be added to the DB.
If you need to load default values into your DB, that might be better done via a custom rake task, independent of migrations.

Resources