5

Rails 7 adds support for `if_exists/if_not_exists` on `remove_foreign_key/add_fo...

 3 years ago
source link: https://blog.saeloun.com/2021/07/14/rails-7-if_exists-if_not_exists-on-remove-add-foreign-key
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Rails 6.1 added support for if_exists/if_not_exists on remove/add column and extended it further to support if_not_exists on add_index and if_exists on remove_index.

To maintain the same behavior across add/remove constraints of databases, Rails 7 added support for if_exists/if_not_exists on remove_foreign_key/add_foreign_key.

Before Rails 7

Add foreign key

Let’s say we have an e-commerce application with Order and User models. An order belongs to a user, and we want to add a user_id foreign key constraint on the orders table. We would add a migration as shown below:

class AddUserReferenceToOrder < ActiveRecord::Migration[6.0]
  def change
    add_foreign_key :orders, :users
  end
end

But if the orders table already contains foreign_key constraint on the user, the above DB migration will raise an error.

rails db:migrate

== 20210714080612 AddUserReferenceToOrder: migrating ================
-- add_foreign_key(:orders, :users)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DuplicateObject: ERROR:  constraint "fk_rails_11f1189a77" for relation "orders" already exists

Remove foreign key

Similarly, if we try to remove a foreign_key constraint that never existed on orders table the migration would also raise an error.

class RemoveProductReferenceFromOrder < ActiveRecord::Migration[6.0]
  def change
    remove_foreign_key :orders, :products
  end
end

rails db:migrate

== 20210714080712 RemoveProductReferenceFromOrder: migrating ================
-- remove_foreign_key(:orders, :products)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

Table 'orders' has no foreign key for products

In Rails 7

To avoid above issues and to keep things consistent, Rails team added support to pass if_exists/if_not_exists options to remove_foreign_key/add_foreign_key.

With this change, the below migrations run successfully without raising any error.

Add foreign key

class AddUserReferenceToOrder < ActiveRecord::Migration[6.0]
  def change
    add_foreign_key :orders, :users, if_not_exists: true
  end
end

rails db:migrate

== 20210714080612 AddUserReferenceToOrder: migrating ================
-- add_foreign_key(:orders, :users, {:if_not_exists=>true})
   -> 0.0151s
== 20210714080612 AddUserReferenceToOrder: migrated (0.0153s) ==================

Remove foreign key

class RemoveProductReferenceFromOrder < ActiveRecord::Migration[6.0]
  def change
    remove_foreign_key :orders, :products, if_exists: true
  end
end

rails db:migrate

== 20210714080712 RemoveProductReferenceFromOrder: migrating ================
-- remove_foreign_key(:orders, :products, {if_exists: true})
   -> 0.0118s
== 20210714080712 RemoveProductReferenceFromOrder: migrated (0.0118s) ================

Check out this pull request for more details.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK