[Ruby] I implemented polymorphic related things at Nogizaka.

2 minute read

About polymorphic

Somehow it’s difficult to stick to, so after a while studying, it becomes polymorphic …? So I enjoyed implementing it. It’s a memorandum, so please take a quick look.

Normal association

Implementing which hill group sings which song without defining polymorphic associations…

``

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

problem

  • If you want to get information about an idol singing a song, you have to check which idol is singing. (I think if you are a fan of slopes you will understand without checking … lol)

``


@song = Song.take # Get instance appropriately
@song.nogizaka # For Nogizaka46 songs
@song.hinatazaka # For Hyugazaka46 song
  • When we have 46 groups, we need to add columns to the song model.

Implemented in polymorphic

  • Just set polymorphic: true to references

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 #Coco! !!
      t.timestamps
    end
  end
end

schema.rb


create_table "songs", force: :cascade do |t|
    t.string "name"
    t.string "postable_type" #type distinguishes Nogizaka class or Keyakizaka class
    t.integer "postable_id"
    ...(Omitted)
  end

I will also rewrite the models. It’s surprisingly easy.

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 line is now 1 line!
end

What happens in #???

When #@song is Nogizaka's song
# Normal association
@song.nogizaka # => name:"Nogizaka46", year_of_formation:2011,...
# Polymorphic related
@song.songable # => name:"Nogizaka46", year_of_formation:2011,...
  • Above, you can get an instance of the same Nogizaka model
  • I’d be happy if you could get some kind of image.

You can also write like this

Define the same name method in each model and change the behavior in it.

class Nogizaka <ApplicationRecord
  has_many :songs, as: :songable

  def cute_member
   "Name: #{name}, pet: #{pet_name}"
  end
end


class Keyakizaka <ApplicationRecord
  has_many :songs, as: :songable
  
  def cute_member
   "Name: #{name}, birthplace: #{birthplace}"
  end
end


class Hinatakizaka <ApplicationRecord
  has_many :songs, as: :songable

  def cute_member
   "Name: #{name}, Catch Copy: #{catch_copy}"
  end
end

Result

``


When #@song is Nogizaka
@song.songable.cute_member
=> "Name: Yuki Yoda, Pet: Gonzou"

When #@song is Keyakizaka
@song.songable.cute_member
=> "Name: Hikaru Morita, Birthplace: Fukuoka Prefecture"

When #@song is Hyugazaka
@song.songable.cute_member
=> "Name: Hinano Uemura, catchphrase: Hinano Nano!"

Summary

  • You can get an instance of Nogizaka model (Keyakizaka, Hyugazaka) with @song.songable. (I think it’s around here that it’s hard to get an image and it makes polymorphic difficult.)
  • Idols are cute as expected. .. ..