views:

452

answers:

4

I want a migration to create a clone of an existing table by just suffixing the name, including all the indexes from the original table.

So there's a "snapshots" table and I want to create "snapshots_temp" as an exact copy of the table (not the data, just the table schema, but including the indexes).

I could just copy and paste the block out of the schema.rb file and manually rename it.

But I'm not sure by the time this migration is applied if the definition from schema.rb will still be accurate. Another developer might have changed the table and I don't want to have to update my migration script.

So how might I get the schema of the table at runtime? Essentially, how does 'rake schema:dump' reverse engineer the table so I can do the same in my migration? (but changing the table name).

A: 

It looks like this logic is wrapped up in ActiveRecord::SchemaDumper but it only exposes an all-in-one "dump" method and you can't dump just a specific table (the "table" method is private).

Teflon Ted
A: 

This will do. It's not perfect, because it won't copy table options or indices. If you do have any table options set, you will have to add them to this migration manually.

To copy indices you'll have to formulate a SQL query to select them, and then process them into new add_index directives. That's a little beyond my knowledge. But this works for copying the structure.

class CopyTableSchema < ActiveRecord::Migration
  def self.up
    create_table :new_models do |t|
      Model.columns.each do |column|
        next if column.name == "id"   # already created by create_table
        t.send(column.type.to_sym, column.name.to_sym,  :null => column.null, 
          :limit => column.limit, :default => column.default, :scale => column.scale,
          :precision => column.precision)
      end
    end

    # copy data (optional)

    Model.each do |m|
      NewModel.create m.attributes
    end
  end

  def self.down
    drop_table :new_models
  end
end
EmFi
> it won't copy table options or indicesThanks but indexes is a requirement.
Teflon Ted
+2  A: 

Try doing it with pure SQL. This will do what you want:

CREATE TABLE new_tbl LIKE orig_tbl;
zenazn
Good call. "Use LIKE to create an empty table based on the definition of another table, including any column attributes and indexes defined in the original table" http://dev.mysql.com/doc/refman/5.1/en/create-table.html
Teflon Ted
Works with MySQL (and possibly most databases) but if you use Sqlite, it won't work. I ran into this problem in development environment. Production is fine (it's MySQL).
MiniQuark
A: 

That seems extremely slow for large amounts of data...

RedRubyNike