Rails 7 - Bổ sung option "if_exists/if_not_exists" khi thêm/xóa foreign_key trong migration ⛑️⛑️⛑️
Hello mọi người, lại là Tiến đây. Hôm nay mình sẽ chia sẻ mọi người chút thay đổi ở version Rails 7 mới nhất nhé.
Rails 6.1 đã thêm hỗ trợ cho if_exists/if_not_exists
trên loại để add/remove column và mở rộng nó hơn nữa để hỗ trợ if_not_exists
trên add_index
và if_exists
trên remove_index
.
Để duy trì cùng một hành vi trên các rằng buộc add/remove của database, Rails 7 đã bổ sung hỗ trợ if_exists/if_not_exists
trên remove_foreign_key/add_foreign_key
trong migration.
Before Rails 7 ⛹️⛹️⛹️
Add foreign key 🤔
Giả sử chúng ta có 2 bảng Order
và User
, Order
sẽ thuộc về(belongs_to) một User
. Chúng ta sẽ thêm user_id
làm foreign_key vào bảng Order
. Thể hiện migration sẽ như sau:
class AddUserReferenceToOrder < ActiveRecord::Migration[6.0]
def change
add_foreign_key :orders, :users
end
end
Nhưng nếu bảng Order
đã có khóa ngoại user_id
đối với User
, migration sẽ raise lỗi ❌❌❌
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 🤔
Tương tự, nếu chúng ta cố gắng loại bỏ foreign_key user_id
trên bảng Order
nhưng nó không tồn tại ở bảng Order
thì cũng sẽ raise lỗi ❌❌❌
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 🤾🤾🤾
Để tránh các vấn đề trên và giữ mọi thứ được nhất quán. Team phát triển Rails đã bổ sung thêm option if_exists/if_not_exists
để remove_foreign_key/add_foreign_key
. Với sự thay đổi này, quá trình chạy migration bên dưới sẽ thành công và không gây ra bất kỳ lỗi nào
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) ================
mlem mlem....Hí hí 🤤🤤
Bạn có thể xem chi tiết thay đổi lại tại pull request của source Rails trên Github