2018年2月22日 星期四

用 foreign_key 確保資料相依正確性 (referential integrity)

Rails 4.2 以後開始支援 database 的 foreign key,很好的文章:

https://robots.thoughtbot.com/referential-integrity-with-foreign-keys


我們會用

```rb
class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
end

class Post < ActiveRecord::Base
  belongs_to :user
  validates :user, presence: true
end
```


這種做法來確保 post 有 user,看似沒問題但這些 validation 都在 rails 的 application 層級,而 rails 提供了很多方式讓你跳過這些 validations 和 callbacks,所以是不可信任的。ex:


User.delete_all 會跳過 `dependent: :destroy` callback

更別提我們常常連 `dependent: :destroy` callback 都忘記加(oops~)

所以應該讓 database 加上這個限制確保我們不會不小心搞爆這些資料


```rb
def change
  add_foreign_key :posts, :users
end
```

另外也可以讓 database 幫我們做到 `dependent: destroy` 一樣的事情

```rb
add_foreign_key :posts, :users, on_delete: :cascade
```

會產生 SQL (postgres):


```sql
ALTER TABLE `posts`
ADD CONSTRAINT `posts_user_id_fk`
FOREIGN KEY (`user_id`) REFERENCES `users`(id)
ON DELETE CASCADE;
```

Caveats:rails 的 Polymorphic associations 不適用




沒有留言:

張貼留言