ポリモーフィック関連について
なんとなくとっつきにくいが故に、勉強してしばらく経つとポリモーフィック...?となるので、楽しく実装してみました。備忘録的な感じなので、ゆるっと見ていって下さい。
通常のアソシエーション
どの坂道グループがどの楽曲を歌っているのかを、ポリーモーフィック関連を定義せずに実装すると...
nogizaka.rb
class Nogizaka < ApplicationRecord
has_many :songs
end
keyakizaka.rb
class Keyakizaka < ApplicationRecord
has_many :songs
end
hinatazaka.rb
class Hinatakizaka < ApplicationRecord
has_many :songs
end
song.rb
class Song < ApplicationRecord
belongs_to :nogizaka
belongs_to :keyakizaka
belongs_to :hinatazaka
end
問題点
- ある楽曲を歌うアイドルの情報を取得したい場合、どのアイドルが歌っているのか確認しなくてはならない。(坂道ファンなら確認せずとも分かってしまうと思いますが...笑)
@song = Song.take #適当にインスタンスを取得
@song.nogizaka #乃木坂46の楽曲の場合
@song.hinatazaka #日向坂46の楽曲の場合
- 46グループが増えた時に、songモデルにカラムを追加する必要がある。
ポリモーフィックで実装
-
references
にpolymorphic: true
を設定するだけ
20200620xxxx_create_songs.rb
class CreateSongs < ActiveRecord::Migration[5.2]
def change
create_table :songs do |t|
t.string :name
t.references :songable, polymorphic: true, index: true #ココ!!
t.timestamps
end
end
end
schema.rb
create_table "songs", force: :cascade do |t|
t.string "name"
t.string "postable_type" #typeで乃木坂クラスなのか欅坂クラスなのかを見分けている
t.integer "postable_id"
...(以下略)
end
モデル達も書き換えてあげる。意外と簡単です。
class Nogizaka < ApplicationRecord
has_many :songs, as: :songable
end
class Keyakizaka < ApplicationRecord
has_many :songs, as: :songable
end
class Hinatakizaka < ApplicationRecord
has_many :songs, as: :songable
end
class Song < ApplicationRecord
belongs_to :songable, polymorphic: true
# Before ↓↓↓
# belongs_to :nogizaka
# belongs_to :keyakizaka
# belongs_to :hinatazaka
#3行が1行になりました!
end
で、何が起こるの???
# @songが乃木坂の楽曲の場合
# 通常のアソシエーション
@song.nogizaka # =>name:"乃木坂46", year_of_formation:2011,...
#ポリモーフィック関連
@song.songable # =>name:"乃木坂46", year_of_formation:2011,...
- 上記で、同じ乃木坂モデルのインスタンスが取得できる
- なんとなくのイメージを掴んでもらえれば嬉しいです。
こんな書き方もできます
同名メソッドを各モデルに定義し、その中での挙動を変えます。
class Nogizaka < ApplicationRecord
has_many :songs, as: :songable
def cute_member
"名前:#{name}, ペット:#{pet_name}"
end
end
class Keyakizaka < ApplicationRecord
has_many :songs, as: :songable
def cute_member
"名前:#{name}, 出身地:#{birthplace}"
end
end
class Hinatakizaka < ApplicationRecord
has_many :songs, as: :songable
def cute_member
"名前:#{name}, キャッチコピー:#{catch_copy}"
end
end
結果
#@songが乃木坂の場合
@song.songable.cute_member
=> "名前:与田祐希, ペット:ごんぞう"
#@songが欅坂の場合
@song.songable.cute_member
=> "名前:森田ひかる, 出身地:福岡県"
#@songが日向坂の場合
@song.songable.cute_member
=> "名前:上村ひなの, キャッチコピー:ひなのなの!"
まとめ
-
@song.songable
で乃木坂モデル(欅坂、日向坂)のインスタンスが取れる。(イメージがつきにくく、ポリモーフィックを難解にしているのはこの辺りな気がしました。) - アイドルはやっぱり可愛い。。。