Drop a table in production

In this post, we will see an approach how to safely drop a table from a production application without running into weird issues.

As an example, we will use a simple blog that allows adding comments to each post and also has a simple stats table where it tracks likes, views, and shares of posts.

The model diagram for this example is the following:

From the application, we are interested in the schema file and the Stat class:

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

# db/schema.rb

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

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

t.string"username"

t.string"content"

t.datetime"created_at",null:false

t.datetime"updated_at",null:false

t.integer"post_id"

t.index["post_id"],name:"index_comments_on_post_id"

end

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

t.string"title"

t.string"content"

t.datetime"created_at",null:false

t.datetime"updated_at",null:false

end

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

t.integer"likes"

t.integer"views"

t.integer"shares"

t.datetime"created_at",null:false

t.datetime"updated_at",null:false

t.integer"post_id"

t.index["post_id"],name:"index_stats_on_post_id"

end

end

The stat class:

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

# app/models/stat.rb

classStat<ApplicationRecord

belongs_to:post

class<<self

defon_like(post_id)

stat=Stat.find_by(post_id:post_id)

stat.increment!(:likes)

end

defon_view(post_id)

stat=Stat.find_by(post_id:post_id)

stat.increment!(:views)

end

defon_share(post_id)

stat=Stat.find_by(post_id:post_id)

stat.increment!(:shares)

end

end

end

Our task is to remove the stats table because we will be using a third party provider for tracking. So let’s get started:

1- Search and Update

This is the most crucial step, it depends on the project size and it requires patience and precision.

Generally, we want to perform the search using this order:

The class name to delete

Possible association of the model

Method names of the model

2- Testing:

At this point, we will have some failing tests, so we need to update those tests to make the suite green again!.

We should keep in mind that we should also do some manual testing too. It’s not just clicking through the application but we need to keep an eye on our logs to check for warnings.

3- Check background jobs

This step depends on the project, in our example let’s pretend that we have a background job that processes our blog stats weekly to generate a report.

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

14

# app/jobs/generate_stats_report_worker.rb

classGenerateStatsReportWorker

includeSidekiq::Worker

defperform(stat_ids)

stats=Stat.where(id:stat_ids)

reports=generate_report(stats)

send_reports

end

end

This worker will be scheduled to execute with an array of Stat ids as parameters. It’s clear that we will have a lot of errors if we drop the Stat model while this job is still in the scheduled queue. So what to do in this case?

There is no concrete answer to this question, it depends on the importance of the background job, the best tip for this case is to check with your project manager or your senior colleagues. But the main two options are:

Delete the enqueued jobs

Run the enqueued jobs before deploying the changes.

4- Deployment

Finally, we reached the last step in the process, we are ready now to deploy our changes.

So it’s time to add the migration:

Ruby

1

2

3

4

5

classDropStatsTable<ActiveRecord::Migration[5.2]

defchange

drop_table:stats

end

end

There are different recipes in deployment, so to be sure that we don’t end up in a state where our code in production relies on the existence of Stats table while it’s dropped, we need to submit two pull requests.

The first pull request will include only code changes without dropping the table

The second pull request will include the drop migration

That’s it, we saw together a four steps process to delete a table from production with confidence! So have fun and keep coding 🙂