ドグサレ初心者のへっぽこビッグウェーブ

地球の底辺にいるゴミがプログラミングとか音楽とかを語るクソブログ

アソシエーション(関連)とはなんぞ

テーブルのアソシエーションを勉強しようとしたら色々と足りなかったので追加。
別になくてもいいんだけど、教科書通りに検証しようとすると色々足りないので付け足してる。

  • 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

という感じ。


難しいな。。。。