Railsのポリモーフィック関連　初心者→中級者へのSTEP10/25

#Railsのポリモーフィック関連
**はじめに**
今回はポリモーフィック関連についてです。
はて、ポリモーフィックとは？の方ように、ポリモーフィックについて簡単に説明して、実際に実装してみたいと思います。


##ポリモーフィズムとは##
`Polymorphism`、意味は多様性。オブジェクティブ指向の３大要素にもありますね（ポリモーフィズム）。
一言でいうと、オブジェクトの実態を気にせず、メソッドを呼び出し、そのオブジェクトごとに振舞ってもらうことです。
豚さん、鴨さん、犬さんがいたとして、３人の鳴き声を聞きたいときに、

「ブヒブヒって言ってください」
「クワクワと叫んでください」
「ワンワンと鳴いてください」

とそれぞれの振る舞いごとに命令をいうのではなく、３匹共に

「鳴いてください。」

と命令した方が楽だし、いちいち命令先の動物達のことを考えて命令しませんよね。
プログラミングでも同じで、いちいちオブジェクトの実態のことを考えてコードを書いていたらコードは汚くなるし、大変です。鳴き声を出力するメソッド（命令）は全部同じ名前で使いたいのです。鳴き声についてはオブジェクトごとに勝手に変わってくれればいいのです。
さてポリモーフィズムはオブジェクティブ指向の話なので、まあこんなところで切り上げます。

今回は`ポリモーフィック関連`です。

##ポリモーフィック関連##
ポリモーフィック関連とは上記のポリモーフィズムの思想の元、モデルを関連づけることです。
例えば、`Userモデル`と`Companyモデル`の二つが`Postモデル`を共有している場合、
記事の所有者が企業なのか、個人ユーザーなのかの２通りあります。
ポリモーフィックを使わない場合、

```User.rb
class User < ApplicationRecord
  has_many :posts
end
```

```Combany.rb
class Company < ApplicationRecord
  has_many :posts
end
```

```Post.rb
class Post < ApplicationRecord
  belongs_to :user
  belongs_to :campany
end
```

上記３つのコードで一応、関連はつけられてます。しかし、問題が２つあります。

１、記事の投稿者の情報を取得する場合、Userなのか、Companyなのか確認しなければなりません。
２、投稿するモデルが増えた場合、Postモデルにカラムを追加して関連づけなければならない。

これらを解決するためにポリモーフィック関連を使って、オブジェクトの実態のしがらみから解放されましょう。

##ポリモーフィック関連を実装してみる##
実装は簡単です。

```create_post.rb
class CreatePost < ActiveRecord::Migration[5.1]
  def change
    create_table :posts do |t|
      t.string  :name
      t.references :postable, polymorphic: true, index: true
      t.timestamps
    end
  end
end
```
前回学んだ`reference`を用いて参照するためのキーをカラムに追加します。そのときにオプションで`polymorphic`をtrueにするだけです。これで`postable`を使って関連した投稿者を取得できます。

これスキーマ見ればわかるんですけど、自動でpostable_typeってのが追加されてるんですよね。ここで投稿者のクラスを判断してるみたいです。

```schema.rb
  create_table "posts", force: :cascade do |t|
    t.string "name"
    t.string "postable_type"
    t.integer "postable_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["postable_type", "postable_id"], name: "index_posts_on_postable_type_and_postable_id"
  end
```

あとは、各々のモデルで関連づけるだけです。

```rb
class Post < ApplicationRecord
  belongs_to :postable, polymorphic: true
end

class User < ApplicationRecord
  has_many :posts, as: :postable 
end

class Company < ApplicationRecord
  has_many :posts, as: :postable
end

```

これで`@post.postable`で投稿者がどっちのクラスか気にせず呼び出せます。
さて、ポリモーフィズムにのっとるなら、共通のメソッドの定義しましょう。

```rb
class User < ApplicationRecord
  has_many :posts, as: :postable 

  def contributor_name
    "#{last_name} #{first_name}"
  end
end

class company < ApplicationRecord
  has_many :posts, as: :postable

  def contributor_name
    name
  end
end
```

これで記事の投稿者の名前出力はオブジェクトの実態を気にせず全部共通で`@post.postable.contributor_name`で出力されます。しかも個人ユーザーか、企業かで名前の表記の振る舞いも各々に応じたものになります。
これが簡単なポリモーフィックの例です。

##まとめ
最後のメソッドの定義は必須な仕様にはなってないみたい。そこを実装するかはコーダーの腕ってとこなのかね。オブジェクティブ指向は考え方みたいなものだから、難しいね。そちらも深めていきたい。
今回は参考記事がワシなに書けばいいんだろうってくらい良記事だったのぜひ。

##参考にしたの

Railsのポリモーフィック関連とはなんなのか
https://qiita.com/itkrt2y/items/32ad1512fce1bf90c20b

【Rails】ActiveRecord：単一テーブル継承(sti)とポリモーフィック関連を未だにぱっと思い出せないのでまとめ。
https://shirusu-ni-tarazu.hatenablog.jp/entry/2012/11/04/173742

Active Record の関連付け (アソシエーション)
https://railsguides.jp/association_basics.html#%E3%83%9D%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91