💡
【Rails】modelの外部キーにnullが入ることを許可する
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