アソシエーション(関連)とはなんぞ
テーブルのアソシエーションを勉強しようとしたら色々と足りなかったので追加。
別になくてもいいんだけど、教科書通りに検証しようとすると色々足りないので付け足してる。
- record、helloのコントローラを追加
> rails generate controller record > rails generate controller hello
- helloでmusicsの一覧を見れるようにする
- hello_controller.rbで list呼び出し時に@musics読み込み
- hello/list.html.erbに@musicを読み込むテーブル記載
- このままだとhelloにルート通ってないので、route.rbにルーティング追加
get '/hello/list' => 'hello#list'
- データ取得のためのコントローラrecordにもルートを通す
get '/record/find' => 'record#find'
準備完了。
ここからアソシエーションのはなし
アソシエーションの定義はモデルに対して実施する。
参照元(外部キーを持つ)テーブルから参照先(主キーを持つ)テーブルにアクセス
belongs_to :hoge
元と先が1:nの関係を表す
has_many :hoges #"s"が付く
元と先が1:1の関係を表す
has_one :hoge
元と先がm:nの関係を表す(中間テーブルを利用する)
has_and_belongs_to_many :hoges
※中間テーブル:それぞれのテーブルのキーのみを持つテーブル。
命名規則があり、参照先のテーブル名をアルファベット順にアンダーバーで連結したもの。
→例えば、hogeとgegeの中間テーブルは「geges_hoges」となる
元と先がm:nの関係を表す(中間テーブル以上の情報が含まれるテーブルが挟まる場合)
has_many :users, through: :reviews #hogehogesは挟まっているテーブル
オプション
関連の命名を変更するオプション
※「artist」モデルに対して1:nの関係である「funcomment」モデルを追加する
[要件が以下の場合]
a. artistモデルからFanCommentモデルを(fan_commentsメソッドではなく)commentsメソッドで参照
b. fan_commentsテーブルの外部キーは(「artist_id」ではなく)「artist_no」
c. artistモデルからFanCommentモデルを取得する際、deleted列が「false(未削除)」であるもののみ抽出
[artist.rb]
a. 関連名は自由、そのかわりオプションで関連先のクラスを宣言
→ "has_many :comments, class_name: 'FanComment',"
b. 関連を形成する際の外部キーの指定、命名が異なる場合にはオプションで明示的に宣言
→ "foreign_key: 'artist_no'"
c. FanCommentモデルを参照する際の条件式をラムダ式(->{...})で指定
→ "->{where(deleted: false)},"
。。。で、最終的なアソシエーションメソッドはこうなる。
has_many :comments, ->{where(deleted: false)}, class_name: 'FanComment', foreign_key: 'artist_no'
関連モデルの件数を親モデル側でキャッシュ(カウンターキャッシュ)
1: カウンター管理のための列(integer型)を親テーブルに準備
→マイグレーションファイルのカウンタ列に「default: 0」をセット
2: カウンターキャッシュ機能を有効にする
→子モデルのbelongs_toのオプションに「counter_cache: true」を追記
※命名規則あり、カウンタ列が「子テーブル名_count」という名前でない場合は、
「counter_cache: :hogehoge_num」のように、明示的に列名を指定する必要あり
ひとつのモデルを複数の親モデルに関連付ける(ポリモーフィック関連)
- 通常の外部キーでは紐付けを表現できないので、以下の列をテーブルに準備する必要あり
(紐付けるモデル):xxxxx_type
(外部キー):xxxxx_id
※ "xxxxx"は宣言時に指定する関連名を表す。
- 各モデルでは以下のような宣言が必要。
1:親モデル側でasオプション付きのhas_manyメソッドを宣言
has_many :memos, as: :memoable
2:子モデル側でpolymorphicオプション付きのbelongs_toメソッドを宣言
belongs_to :memoable, polymorphic: true
まとめると、
- 子のテーブルに「xxxxx_type」「xxxxx_id」という列を作成
- 親モデル側に「as: xxxxx」というオプションをつけたhas_many
- 子モデル側に「polymophic: true」というオプションをつけて、xxxxxを引数にしたbelongs_to
という感じ。
難しいな。。。。