表題のとおりなのですが。
class Post < ApplicationRecord belongs_to :user end
↑のように書いたときに、Rails5からは自動でvalidation_presence_of :user
としたのと同じになります。postをバリデーションするときにuserの存在をチェックする必要があるので、userが未ロードであればクエリが発行されます。一度にたくさんのpostを保存するようなケースでN+1が発生して困った経験がある人もいるのではないでしょうか。
./bin/rails g model post user:references
のようにした場合は、次のように外部キー制約とbelongs_to
が両方定義された状態になりますね。
class CreatePosts < ActiveRecord::Migration[6.0] def change create_table :posts do |t| t.references :user, null: false, foreign_key: true t.timestamps end end end
class Post < ApplicationRecord belongs_to :user end
しかし、PostからUserへ外部キー制約を貼っていればvalidation_presence_of :user
は不要では?という気がします。むしろ無駄にクエリが発行される分マイナスなような気もする。
次のようにすればOKではあるけれど、実際は必須なのにoptional: true
と書かなければいけないなのが大変微妙。
class Post < ApplicationRecord belongs_to :user, optional: true end
と、ここまで書いていて気がついたけど論理削除のようなしくみを採用していた場合は外部キー制約では不十分ですね…とりあえず今回のケースではそれは考慮しないとします…><
このへん、みんなどのように解決しているのでしょうか?コメントほしいです(\( ⁰⊖⁰)/)
- 外部キーを使っておらず、
belongs_to
によるバリデーションを利用している - Railsが生成するデフォルトのように、外部キーと
belongs_to
によるバリデーションを両方使っている - 外部キーのみ使用しており、
belongs_to
によるバリデーションはオフにしている - その他
追記
- 同じようなことを考える人はやっぱりいてgemが作られていました
- toptal/database_validations: Database validations for ActiveRecord