Rename an ActiveRecord model

Choosing a good name for a class or a variable isn’t easy at all and sometimes there is a requirement to rename existing tables and models to match the updated product audience.

So how we should do this migration then:

1- Ask why

The first step is to ask why should we rename the model, with a productive mindset and a good set of questions you will be surprised that in most cases a renaming is not required at all!

2- Change the model name

It seems that this case requires to rename the ActiveRecord model, so let’s use the following example:

Ruby

1

2

3

4

5

# app/models/author.rb

classAuthor<ApplicationRecord

has_many:books

end

Ruby

1

2

3

4

5

# app/models/book.rb

classBook<ApplicationRecord

belongs_to:author

end

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

# db/schema.rb

ActiveRecord::Schema.define(version:2018_06_09_111650)do

create_table"authors",force::cascadedo|t|

t.string"name"

t.datetime"created_at",null:false

t.datetime"updated_at",null:false

end

create_table"books",force::cascadedo|t|

t.string"title"

t.datetime"created_at",null:false

t.datetime"updated_at",null:false

t.integer"author_id"

t.index["author_id"],name:"index_books_on_author_id"

end

end

As we can see we have an Author model who has many Books and our requirement is to rename Author model to Writer.

We start by renaming the Author model file and mapping the new model to the existing authors table. Also, we need to specify the foreign key for the association to be able to access associated books.

Ruby

1

2

3

4

5

6

7

8

# app/models/author.rb -> app/models/writer.rb

classWriter<ApplicationRecord

self.table_name="authors"

has_many:books,foreign_key:'author_id'

end

Let’s update the Book model by specifying the existent foreign key. This step is important to maintain the belongs_to association.

Ruby

1

2

3

classBook<ApplicationRecord

belongs_to:writer,foreign_key:'author_id'

end

I guess that you are asking why should we bother with this step instead of renaming the models and tables at the same time.

To answer this good question, we should consider how applications look like in production. Usually, models may have different associations and used in different parts of the application like controllers and services. That’s why we do this process step by step to be sure that our application is still working as expected before changing the tables and columns in the database.

3- Run the test suite

At this point, we must run our test suite and be sure all specs are passing before moving to the last step. This step is very important to be sure that we didn’t break an existent feature during the migration.

4- Rename DB tables and columns

Now we are ready for the last step, so let’s write some migrations. We start by renaming the authors‘ table to writers.

Ruby

1

2

3

4

5

classRenameAuthorsToWriters<ActiveRecord::Migration[5.2]

defchange

rename_table:authors,:writers

end

end

Then we need to rename the foreign key from author_id to writer_id.

Ruby

1

2

3

4

5

classRenameFkInBooks<ActiveRecord::Migration[5.2]

defchange

rename_column:books,:author_id,:writer_id

end

end

And finally, we clean up our models.

Ruby

1

2

3

4

5

# app/models/writer.rb

classWriter<ApplicationRecord

has_many:books

end

Ruby

1

2

3

4

5

# app/models/book.rb

classBook<ApplicationRecord

belongs_to:writer

end

Here is the updated schema, we can check that renaming the column took care of renaming the index. But we should keep in mind this only valid for Rails version >= 4.0 as stated in this changelog:

In Rails 4.0 when a column or a table is renamed the related indexes are also renamed. If you have migrations which rename the indexes, they are no longer needed.