Railsのアソシエーションと複数登録 ~モデルの準備~
Facebook等からユーザー情報を持ってくる場合は、個人的には別テーブルに詳細情報をもたせたい。
詳細情報が各項目必ず一つであれば詳細テーブル内に入れてしまえば良いが、
例えば経歴だったり資格だったり、複数持つ情報の場合は詳細テーブルだけでは事足りない。
そんな時のアソシエーションの備忘録 (・ω・)
はじめに
OAuth認証でログインしてきた人に追加で必要な情報を入力させる画面を想定してみる。
今回はそこに持っているゲーム機とゲーム経験を登録させる。
このあたりのデータはなんでも良いが、特定のリストから選択と自由入力項目を複数同時に登録出来るような入力画面を作成する。
要件定義
ざっくりと大体↓こんな感じ。
- Userは一つのProfileを持つ
- Profileは複数のゲーム機を持つ
- ゲーム機名称は別テーブルで持たせて、選択させる
- Profileは複数のゲーム経験を持つ こちらは自由入力
モデルを作成する
まずは必要なモデルを作る。
class User < ApplicationRecord # OAuth認証を想定して最低限の情報で end class Profile < ApplicationRecord # 入力してほしい情報はすべてここに集約 end class GameCareer < ApplicationRecord # ゲーム経験 end class GameConsole < ApplicationRecord # 所持しているゲーム機 end class PossessGame < ApplicationRecord # 所持してるゲーム機とプロフィールをつなげる中間テーブル # 今回は繋げるだけなのでIDしか用意し無いが、例えば購入日等あればここに乗せても良い。 end
アソシエーションを組む
ユーザーとプロフィール
class User < ApplicationRecord has_one :profile, dependent: :destroy end class Profile < ApplicationRecord belongs_to :user end
ユーザーは必ず1つ(2以上はありえない)のプロフィールを持つのでhas_one
で繋げる。
belogns_to
側にIDを入れる必要があるので、Userをhas_one,Profileをbelongs_toとする。
プロフィールとゲーム経験
class Profile < ApplicationRecord has_many :game_careers, dependent: :destroy end class GameCareer < ApplicationRecord belongs_to :profile end
プロフィールは複数のゲーム経験を持つので、has_many
で繋げる。
プロフィールと持っているゲーム機
class Profile < ApplicationRecord has_many :possess_games, dependent: :destroy end class PossessGame < ApplicationRecord belongs_to :profile belongs_to :game_console end GameConsole < ApplicationRecord has_many :possess_games end
中間テーブルが出て来るが基本的に同じ。やってることは名称のマスタ化。(いわゆる第二正規化)
これでProfile - PossessGame と PossessGame - GameConsoleは繋がったが、
このままだとプロフィールから直接持っているゲーム機を取得するのが面倒なので
ProfileとGameConsoleを繋げる。
class Profile < ApplicationRecord -省略- has_many :games, through: :possess_games, source: :game_consoles end GameConsole < ApplicationRecord -省略- has_many :profiles, through: :possess_games end
through: :possess_games
とすると、中間テーブルを介してデータを取得出来る。
また、has_manyの後にaliasを定義し、sourceでモデル(テーブル名)を指定すると@profile.○○
と別名で呼べるので、モデル名が無駄に長いときやわかりにくい時に便利。
一応直接繋げない場合でも↓のように呼び出すことが可能。
@profile.possess_games.map{|game|game.game_console}
ここまでで、アソシエーションが完了。
seedで適当なデータを登録してConsoleを叩くと、データが取得できる。
アソシエーションの詳細はreflect_on_all_associations
メソッドで確認できるので、モデルから何のデータが呼べるのか確認する場合は、nameを取得すると一発。
pry(main)> Profile.reflect_on_all_associations.map(&:name) => [:user, :game_careers, :possess_games, :games] >>> Profileから以下の4つが呼び出せる。 @profile.user @profile.game_careers @profile.possess_games @profile.games
次は登録画面を作成していく。