💡

【Rails】modelの外部キーにnullが入ることを許可する

2023/04/08に公開

TL;DR

  • 外部キーにnullを許容するためには、モデルの設定でoptional: trueを設定すればよい。

環境

  • Rails 7.0.4

問題と結論

  • Railsで、あるモデルのカラムに、別のモデルを外部キーとして設定している場合、そのカラムがnullであるとレコードを更新できない。更新できるようにしたい。
  • 例: ユーザー情報の登録を、ページを分けてステップで更新していく場合。

詳細

前提

  • Userモデルが、Prefectureモデルを外部キーで参照している。(ユーザー情報の「住んでいる県」の表示のため)
MySQL [DBNAME]> show columns from users;
+------------------------------+--------------+------+-----+---------+----------------+
| Field                        | Type         | Null | Key | Default | Extra          |
+------------------------------+--------------+------+-----+---------+----------------+
| id                           | bigint       | NO   | PRI | NULL    | auto_increment |
| birthday                     | date         | YES  |     | NULL    |                |
| prefecture_id                | bigint       | YES  | MUL | NULL    |                |
...省略...
  • Railsでは以下のように記述
user.rb
class User < ApplicationRecord

  belongs_to :prefecture

エラー

  • Railsコンソールで検証
> user = User.find (xx)
> user.birthday = ほげほげ(適切な値)
=> ほげほげ
irb(main):007:0> user.save!
/usr/local/bundle/gems/activerecord-7.0.4/lib/active_record/validations.rb:80:in `raise_validation_error': バリデーションに失敗しました: Prefectureを入力してください (ActiveRecord::RecordInvalid)
  • ちなみに、save!save!(validate: false)とすると更新可能
    • => これにより、MySQL等のデータベース側のエラーではなく、アプリケーションコードのエラーであることを特定できる。

解決

  • optional: trueを追記
user.rb
class User < ApplicationRecord

  belongs_to :prefecture, optional: true

補足

  • 筆者の実際の環境では、Userモデルではないため、記事内容を正確に自分で実験したわけではないが、同様の構造のmodelで検証済み。記事化のため簡潔にしている。

Discussion