419

I'm terrible at naming and realize that there are a better set of names for my models in my Rails app.
Is there any way to use a migration to rename a model and its corresponding table?

strivedi183
  • 4,408
  • 2
  • 25
  • 34
readonly
  • 306,152
  • 101
  • 198
  • 201
  • 11
    I suggested adding "ActiveRecord" to this question to improve search engine matches. I've been looking for this using "ActiveRecord rename table". – Landon Kuhn Nov 03 '09 at 23:04
  • 6
    If you are using migrations, this problem is more complicated than it seems. The selected solution says to just go back and manually rename the model, controller, etc. after you've changed the table name. If you do this, all older migrations that refer to your model by its older name will fail. So when someone clones your repo and tries to run `rake db:migrate`, it will fail. You could go back and change those names in the migration, but that will get messy. You might be better off just creating an entirely new model rather than renaming it. – andrew Dec 26 '12 at 21:10
  • 4
    @andrewhannigan: Isn't your point moot if someone clones your repo and just runs `rake db:schema:load`? – istrasci Jun 19 '13 at 19:00
  • 3
    @istrasci: absolutely. In fact, running `rake db:migrate` to set up a database from scratch is actively discouraged, exactly because of the concerns pointed out by andrew. – Giuseppe Sep 03 '13 at 05:21

5 Answers5

598

Here's an example:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def self.up
    rename_table :old_table_name, :new_table_name
  end

  def self.down
    rename_table :new_table_name, :old_table_name
  end
end

I had to go and rename the model declaration file manually.

Edit:

In Rails 3.1 & 4, ActiveRecord::Migration::CommandRecorder knows how to reverse rename_table migrations, so you can do this:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def change
    rename_table :old_table_name, :new_table_name
  end 
end

(You still have to go through and manually rename your files.)

ndnenkov
  • 33,260
  • 9
  • 67
  • 97
readonly
  • 306,152
  • 101
  • 198
  • 201
  • Yes but this doesn't change the name of the model, does it? – ryeguy Jan 29 '10 at 21:37
  • it changes only the table name. – Ju Nogueira Mar 03 '10 at 18:58
  • Does this mean you have to rename the Controller and View folders/files manually as well? Are those all of the things to manually rename? – user5243421 Apr 24 '10 at 06:35
  • 6
    @mathee: yes, you have to change that manually, or using an IDE that can do Ruby refactoring and commit it to your version control system. – pupeno Apr 30 '10 at 09:00
  • 13
    git grep is your friend. I'm renaming an Activity to a Habit right now: `git grep -i activit` is very revealing. – Felix Rabe Jan 26 '12 at 10:56
  • 1
    you have to also change the content of your controller, right? – akmur Feb 02 '12 at 01:05
  • 5
    And don't forget your routes.rb! – Dan Herman Apr 19 '12 at 22:58
  • 27
    Also, just as a heads up, you want to use the plural version of your table name in the rename_table call. – Han Sep 20 '12 at 05:37
  • 1
    Some more ideas on automating the renaming process: http://stackoverflow.com/questions/11924124/how-to-rename-rails-controller-and-model-in-a-project/27376575#27376575 – Dan Aug 26 '15 at 09:47
  • Remember that usualy the table_name is plurla – Mauro Nov 09 '15 at 15:58
  • 1
    If you are new to Rails, you can open migration script with this `rails generate migration RenameOldTableToNewTable`, update the new migration file as suggested and then `rake db:migrate`. If you don't know exact name of the table do `rails console` and `ActiveRecord::Base.connection.tables` to list all tables – laimison Sep 14 '17 at 23:16
71

In Rails 4 all I had to do was the def change

def change
  rename_table :old_table_name, :new_table_name
end

And all of my indexes were taken care of for me. I did not need to manually update the indexes by removing the old ones and adding new ones.

And it works using the change for going up or down in regards to the indexes as well.

bfcoder
  • 2,852
  • 1
  • 25
  • 35
52

The other answers and comments covered table renaming, file renaming, and grepping through your code.

I'd like to add a few more caveats:

Let's use a real-world example I faced today: renaming a model from 'Merchant' to 'Business.'

  • Don't forget to change the names of dependent tables and models in the same migration. I changed my Merchant and MerchantStat models to Business and BusinessStat at the same time. Otherwise I'd have had to do way too much picking and choosing when performing search-and-replace.
  • For any other models that depend on your model via foreign keys, the other tables' foreign-key column names will be derived from your original model name. So you'll also want to do some rename_column calls on these dependent models. For instance, I had to rename the 'merchant_id' column to 'business_id' in various join tables (for has_and_belongs_to_many relationship) and other dependent tables (for normal has_one and has_many relationships). Otherwise I would have ended up with columns like 'business_stat.merchant_id' pointing to 'business.id'. Here's a good answer about doing column renames.
  • When grepping, remember to search for singular, plural, capitalized, lowercase, and even UPPERCASE (which may occur in comments) versions of your strings.
  • It's best to search for plural versions first, then singular. That way if you have an irregular plural - such as in my merchants :: businesses example - you can get all the irregular plurals correct. Otherwise you may end up with, for example, 'businesss' (3 s's) as an intermediate state, resulting in yet more search-and-replace.
  • Don't blindly replace every occurrence. If your model names collide with common programming terms, with values in other models, or with textual content in your views, you may end up being too over-eager. In my example, I wanted to change my model name to 'Business' but still refer to them as 'merchants' in the content in my UI. I also had a 'merchant' role for my users in CanCan - it was the confusion between the merchant role and the Merchant model that caused me to rename the model in the first place.
Community
  • 1
  • 1
armchairdj
  • 930
  • 10
  • 13
29

You also need to replace your indexes:

class RenameOldTableToNewTable< ActiveRecord:Migration
  def self.up
    remove_index :old_table_name, :column_name
    rename_table :old_table_name, :new_table_name
    add_index :new_table_name, :column_name
  end 

  def self.down
    remove_index :new_table_name, :column_name
    rename_table :new_table_name, :old_table_name
    add_index :old_table_name, :column_name
  end
end

And rename your files etc, manually as other answers here describe.

See: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Make sure you can rollback and roll forward after you write this migration. It can get tricky if you get something wrong and get stuck with a migration that tries to effect something that no longer exists. Best trash the whole database and start again if you can't roll back. So be aware you might need to back something up.

Also: check schema_db for any relevant column names in other tables defined by a has_ or belongs_to or something. You'll probably need to edit those too.

And finally, doing this without a regression test suite would be nuts.

Rimian
  • 32,654
  • 13
  • 106
  • 109
  • 12
    As for rails 4.0.0.beta1 migrations, it doesn't necessary to update indexes manually. AR updates it by itself. – freemanoid May 05 '13 at 08:35
1

You can do execute this command : rails g migration rename_{old_table_name}to{new_table_name}

after you edit the file and add this code in the method change

rename_table :{old_table_name}, :{new_table_name}