Rails

【Rails】外部キーのバリデーションチェックを回避するoptional: trueについて簡単にまとめてみた

Rails

 

今回は外部キーのバリデーションチェックを回避するoptional: trueについて簡単にまとめたので解説したいと思います。通常(optional: trueを記載しない場合では)ではoptional: falseになっているとのことですが、trueとfalseではどのような違いがあるのか見ていきましょう。

optional: trueとは

optional: trueとは、アソシエーションによって紐づけられた外部キーの値が存在しない値やnilの場合でも、データベースに保存することができるオプションです。通常、外部キーの値が存在しない値やnilであればバリデーションで弾かれてしまいます。

上記の挙動はRails5以降から導入されました。

 

例えば、ItemモデルとImageモデルが1対多の関係でアソシエーションが組まれているとします。(has_many :imagesbelongs_to :item

# models/item.rb

class Item < ApplicationRecord
  has_many :images
end
# models/image.rb

class Image < ApplicationRecord
  belongs_to :item
end

 

そしてimagesテーブルに外部キーとしてitem_idが格納されています。

ActiveRecord::Schema.define(version: 2021_12_10_024146) do
  create_table "images", charset: "utf8mb4", do |t|
    t.string "url", default: "", null: false
    t.bigint "item_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end
end
Rails5.1以降、主キーのデフォルト型はBIGINTに変更になりました。

 

ここでimagesテーブルに存在しないitem_idと一緒にurlを保存してみます。

しかし、create処理がバリデーションによって弾かれ、以下のように「Item must exist」というエラーが吐き出されてしまいました。

# item_id: 1は存在しない

Image.create!(url: 'https://sample.com', item_id: 1)
=> ActiveRecord::RecordInvalid: Validation failed: Item must exist

 

これが通常の挙動、optional: falseの挙動になります。通常では、外部キーに存在する値が入っていないとバリデーションで弾かれてしまいます。

一方でImageモデルにoptional: trueを記載するとどうなるのでしょうか。

# models/image.rb

class Image < ApplicationRecord
  belongs_to :item, optional: true
end
# item_id: 1は存在しない

Image.create!(url: 'https://sample.com', item_id: 1)
=> <Image:0x00007fc437abf038
   id: 1,
   url: 'https://sample.com',
   item_id: 1,
   created_at: Sun, 12 Dec 2021 10:06:52 UTC +00:00,
   updated_at: Sun, 12 Dec 2021 10:06:52 UTC +00:00>

 

create処理が成功し、存在しないitem_idが保存されていますね。

このようにoptional: trueは、外部キーが存在しない値やnilの場合でもバリデーションに弾かれずに保存処理ができるオプションになります。

まとめ

  • optional: trueとは、アソシエーションによって紐づけられた外部キーの値が存在しない場合でも、データベースに保存することができるオプション
  • 外部キーがないと弾かれてしまう挙動はRails5以降で導入されている
  • 記述方法としては、belongs_toの後にoptional: trueを記述する

参考記事

 

 

今回は外部キーのバリデーションチェックを回避するoptional: trueについて簡単に解説しました。中間テーブルに値を保存する際など、やむを得ずアソシエーション先のバリデーションチェックを一時回避したい場合はoptional: trueをつけて回避してあげてください。