Problem creating table in database

I manually deleted a table in my database through MySQL administrator as well as the db/migrate/foo file that corresponded with it. Now when I try to recreate this table through the terminal I run:

ruby/script/generate model Spec, which works

then

I then put the appropriate information into the db/migrate file. After this when I run rake db:migrate I get an error that says the schema already exists, even though I don't see the table in MySQL admin.

If you share the contents of the migration and the exact error message, we'll be more able to help.

Regards, Craig

Sean,

One thing to keep in mind. Migrations create a table called "schema_info" that tracks the "migration level". If you manually muck with things, it might get out of sync and then the migration rake task won't do the right thing. If you have three migrations you've run, the schema_info should say "3". If not, then things will have trouble. Do a "rake -D" and read up on the rake db:XYZ options (where XYZ are the various namespaced functions you can do). If you can, you might just start the migrations over by migrating back to 0 or even dropping & recreating the db and/or tables.

Another thing, if I read correctly... you had, let's say, 3 migrations, then you manually deleted the stuff from 003_... and the migration file itself. So really you are back to 002. So go and edit the schema_info and set it to 2 (or whatever level you need) and try doing a migration again. That might work.

-Danimal

So I decided to recover a backup copy and work from there. Is there a best practice for deleting a table?

Here is what I was attempting by the way:

class CreateSpecs < ActiveRecord::Migration   def self.up     create_table :specs do |t|       t.column :user_id, :integer, :null => false       t.column :first_name, :string, :default => ""       t.column :last_name, :string, :default => ""       t.column :gender, :string       t.column :birthdate, :date       t.column :occupation, :string, :default => ""       t.column :city, :string, :default => ""       t.column :state, :string, :default => ""       t.column :zip_code, :string, :default => ""     end   end

  def self.down     drop_table :specs   end end

  SQL (0.000000) Mysql::Error: Table 'schema_info' already exists: CREATE TABLE `schema_info` (version int(11))   SQL (0.000000) Mysql::Error: Table 'schema_info' already exists: CREATE TABLE `schema_info` (version int(11))   SQL (0.000166) SELECT version FROM schema_info   SQL (0.000076) SELECT version FROM schema_info   SQL (0.000075) SELECT version FROM schema_info   SQL (0.000072) SELECT version FROM schema_info   SQL (0.000063) SELECT version FROM schema_info   SQL (0.000122) SELECT * FROM schema_info   SQL (0.026480) SHOW TABLES   SQL (0.011537) SHOW FIELDS FROM `sessions`   SQL (0.000749) describe `sessions`   SQL (0.023708) SHOW KEYS FROM `sessions`   SQL (0.000897) SHOW FIELDS FROM `users`   SQL (0.000871) describe `users`   SQL (0.000359) SHOW KEYS FROM `users`

As a rule of thumb, most people don't edit old migrations, especially if the changes in them are already deployed. Instead, write a simple migration that drops the table. To be honest, though, I've never done that (I've only worked seriously on one Rails project so far), and an interesting question occurs to me: since I'd be writing the self.up part of the migration to drop the table, would I really try to recreate it in the self.down part? Anyone have any insights?

Regards, Craig

Yeah,

The whole point of migrations is that they are cumulative. Each migration builds on the previous one(s). So, in essence, you could recreate everything (other than data, usually) by dropping the DB, then remigrating through all of them. And the self.up and self.down is simply to make sure that whatever you "do" in one migration, you "undo" in the self.down, so you can move up or down the migration tree.

Think of it as a series of transformations and anti-transformations. If I have 10 migrations, I should be able to migrate back to #6 (rake db:migrate VERSION=6) then pop up to 8 (rake db:migrate VERSION=8) and whatever else.

Some other thoughts from one whose done quite a few Rails projects:

1) if it's only you, it's less important. Migrations matter a lot more on shared projects. In fact, I've seen some patches that suggest that future versions of Rails will include migration modifications to make name collisions less likely.

For my part, on projects that I'm the only developer, I only use migrations in a post-launch state. Up until then, I'll still use migrations temporarily as I generate new models/scaffolds/controllers/ etc., but then I "flatten" them back into the original 001. So that is my only migration and effectively is the "current state" of the app's schema. I do this by hand... although you could simply copy schema.db into your 001 migration as it's effectively the same thing.

I also built some custom rake tasks to make my life easier. For example, I have "rake db:remigrate" which does the drop table, create table and migrate all in one... saves some typing. And I have a "rake data:load" which cranks through a bootstrap file and loads a bunch of data. I used to just use the fixture data, but I prefer a bootstrap option because it's just a normal Ruby class (with all the Rails environment, though) and I can do console-like calls. (I know there are options to incorporate this into fixtures, but I decided not to go that route).

2) Once you've "launched", it's a different world. From that point on, you can't (or rather... "really don't want to") roll back migrations. If you launched with only a 001 migration, that one becomes sacrosanct. So any changes start with 002. Then, I usually do the same thing, but 002 is the "baseline". I.e. I "flatten" my migrations down to 002 until the changes are pushed live. Then 002 becomes the new baseline. Etc. Again, this only works if you are the only one one developing... or if you work closely and carefully with the rest of the team.

Craig: one thing: I found this lovely little snippit that I use:

[code]   def self.down     drop_created_tables   end

  def self.drop_created_tables     File.read(__FILE__).scan(/create_table :(\w+)/).each { |table| drop_table table[0].to_sym }   end [/code]

The beauty there is that I don't have to remember to keep the "self.down" method in sync with the "self.up". If I were using multiple migrations with lots of add_columns and the like, this wouldn't work, but with my "flatten" method of working, it's nice. My 001 migration is pretty huge on some large projects, but still easy to navigate through.

-Danimal

Note that Rails 2.1 is changing the way that migrations are tracked.

Instead of using a sequential number, it uses a utc timestamp of the form yyyymmddhhmm, and instead of a single row schema_version table there's a schema_migrations table which has a row for each migration which is currently in effect.

This is quite nice for multi-developer projects, we've been using the enhanced_migrations plugin from revolution healthcare at work for some time which does pretty much the same thing as 2.1 with a different implementation.

It's still possible to do things like collapse multiple migrations down to a checkpoint, but the techniques will be slightly different, and related plugins like automatic_migrations will probably need to be adapted to the new scheme.