optional 関連先の存在チェックをしない
使用可能な関連付け
belongs_to
対となる関連に指定するオプション
なし
概要
以下のようにした場合、関連先のauthor
は必須になる。
class Book < ApplicationRecord
belongs_to :author
end
そのため、以下のvalid?
は全てfalse
になる。
Book.new.valid?
Book.new(author_id: -1).valid?
Book.new(author_id: Author.last.id + 1).valid?
以下のような実際のauthor
に関連している場合だけtrue
になる。
Book.new(author_id: Author.last.id).valid?
Book.new(author: Author.last).valid?
ただし、後者の場合は渡されたauthor
のレコードが削除されていてもvalid?
はtrue
になるので注意が必要。books.author_id
に外部キー制約がされていればActiveRecord::InvalidForeignKey
例外が投げられるが、外部キー制約がされていなければ、そのまま保存されてしまう。
このように関連先が必須というのがデフォルトの挙動だが、optional: true
を指定することで関連先の有無を任意にできる。
belongs_to
の定義を以下のように変える。
class Book < ApplicationRecord
belongs_to :author, optional: true
end
すると、以下のvalid?
もtrue
を返すようになる。
Book.new.valid?
Book.new(author_id: -1).valid?
Book.new(author_id: Author.last.id + 1).valid?
ただし、NOT NULL制約がされていれば最初の例が、外部キー制約がされていれば残り2つの例がsave
を実行したタイミングで例外を投げられるため保存することができない。
validates
による再現
以下の3つは同じ挙動をする(厳密にはvalidates
を使った場合はメッセージが異なる)。
belongs_to :author
belongs_to :author, optional: false
belongs_to :author, optional: true
validates :author, presence: true
以下の例の場合は明確に挙動が異なる。
belongs_to :author, optional: true
validates :author_id, presence: true
この例の場合、author_id
がnil
以外ならバリデーションエラーにならない。先の3つの例はnil
だけでなく実際に関連先が存在することがチェックされる。
config.active_record.belongs_to_required_by_default
Railsの設定項目にoptionalに関するものがある。
元々、belongs_to :author
と書いた場合にはbelongs_to :author, optional: true
と書いた時と同じ挙動をしていた(当時、optional
という設定項目があったかは調べていない)。これがRails 5.0以降はbelongs_to :author, optional: false
と記述した時と同じ挙動に変更されている。
過去の挙動を維持したい場合は、config/application.rb
に以下を追加すれば良い。
# load_defaultsよりもあとに追加
config.active_record.belongs_to_required_by_default = false
ただし、この設定をfalse
にした場合、bin/rails g model book author:belongs_to
などとした時の外部キーにNOT NULL制約が自動では付かなくなる。