Railsのアソシエーション完全入門|belongs_toの必須化とoptional・外部キーの関係をやさしく解説
生徒
「Railsのbelongs_toって書いたら、保存できないことがあるんですが、どうしてですか?」
先生
「belongs_toは、ある相手が必ず存在する前提で使われることが多い仕組みだからです。」
生徒
「optionalって書いてある記事も見ました。それは何ですか?」
先生
「belongs_toを必須にするかどうかを決める設定です。データベースとの関係も含めて説明しますね。」
1. Railsのアソシエーションとbelongs_toの基本
Railsのアソシエーションとは、データ同士のつながりを表現する仕組みです。例えば「注文はユーザーに属する」「コメントは記事に属する」といった関係を、Railsでは簡単なコードで表せます。
belongs_toは、「このデータは必ず相手に所属している」という意味を持ちます。現実世界でたとえると、「生徒は必ずクラスに所属する」「社員は必ず会社に所属する」といった関係です。
Rails初心者の方は、「belongs_to=相手が親で、自分が子」と覚えると理解しやすくなります。
2. belongs_toが必須になる理由
Rails5以降では、belongs_toを定義すると、自動的に必須になります。これは「関連する相手がいないデータは、基本的におかしい」という考え方があるためです。
例えば、ユーザーに属さない注文データがあったら、誰の注文かわからなくなります。このような状態を防ぐため、Railsは最初から厳しめのルールを採用しています。
これはプログラミング未経験の方にとっても、「空欄のまま提出できない申込書」と考えるとイメージしやすいでしょう。
3. optional: true と false の意味
optionalは、「必須かどうか」を切り替えるための設定です。belongs_toに対して使います。
class Post < ApplicationRecord
belongs_to :user
end
この場合、userは必須です。userが存在しないと保存できません。
class Post < ApplicationRecord
belongs_to :user, optional: true
end
こちらは「userがなくても保存してよい」という意味です。optional: falseは省略時と同じで、必須になります。
掲示板の「未ログインでも投稿できるメモ」のような場合に、optional: trueが使われます。
4. バリデーションとの関係
belongs_toが必須になる仕組みは、内部的にはバリデーションが働いています。バリデーションとは、「保存前にチェックする仕組み」です。
post = Post.new(title: "テスト投稿")
post.save
false
userが指定されていないため、保存に失敗します。この時点で、Railsが「関連データがない」と判断しています。
optional: trueを設定すると、このチェックが緩和されます。
5. データベースのNOT NULL制約とは
ここからはデータベース側の話です。NOT NULLとは、「空っぽを許さない」という意味の制約です。
マイグレーションで外部キーにNOT NULLを付けると、データベース自体が「必須」を守ります。
add_reference :posts, :user, null: false, foreign_key: true
これは「Railsが許しても、データベースは許さない」状態を作ります。二重ロックのようなものです。
6. 外部キー制約とbelongs_toの整合性
外部キーとは、「このIDは本当に存在する相手なのか」を確認する仕組みです。存在しないuser_idを入れようとすると、エラーになります。
post.user_id = 9999
post.save
エラーが発生しました
belongs_toが必須、NOT NULLが必須、外部キーあり。この3つがそろうと、非常に安全な設計になります。
7. optionalとNOT NULLの注意点
optional: trueを指定しているのに、データベースでNOT NULLを付けていると、Railsとデータベースの考え方がズレます。
Railsでは「空でもOK」、データベースでは「空はダメ」という状態です。この場合、保存時にエラーが出て初心者は混乱しやすくなります。
設計するときは、「本当に相手がいらないデータか?」を考えてからoptionalを使いましょう。
8. 初心者向け設計の考え方
最初のうちは、belongs_toは基本的に必須のまま使うのがおすすめです。後から「実は不要だった」と気づいたらoptional: trueに変更すれば十分です。
Railsのアソシエーション、belongs_to、外部キー、NOT NULLはすべて「データを壊さないための仕組み」です。鍵付きの引き出しを何重にも用意するイメージで覚えておくと理解しやすくなります。