はじめに
TECH::CAMPで仕事をしている時に、STIとポリモーフォック関連を同時に使える場面があった。設計段階では2つとも使おうと思っていたけれども、実際に実装しようと思ったらポリモーフィズム関連が必要ないことがわかった。
例
例えば、以下のように User
モデルを継承している、 Admin
と NormalUser
があるとする。そして、全てのユーザーが画像をいくつか持っているとする。そうすれば、STIとポリモーフォック関連を使用すると以下のようなコードが出来る。
class User < ActiveRecord::Base
end
class Admin < User
has_many :images, as: :imageable
end
class NormalUser < User
has_many :images, as: :imageable
end
class Image < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
だがしかし、ここで問題なのは image.imageable_type
に本来なら、 Admin
か NormalUser
をいれたいはずなのだが、Railsは親クラスの User
を使う。
そもそもの役割
ポリモーフィック関連
http://qiita.com/itkrt2y/items/32ad1512fce1bf90c20b
こちらのQiitaの記事が非常によく、ポリモーフィックの利点・目的を説明していると思います。結論的にいうと、ポリモーフィック関連は、名前の通り ポリモーフィズム を実装するために使われるものです。
STI
http://qiita.com/yebihara/items/9ecb838893ad99be0561
こちらも非常にいい記事で、この中に 「STIは「継承」の実装、ポリモーフィック関連は「関連」の実装なので、両者を比較するのは不適切です。」という文言がありますが、僕は2つでかぶっている役割があると思います。
理由
ではなぜ、この2つは相容れないのでしょうか。それは、STIがポリモーフィズムも含めて実装してしまえるからです。突き詰めれば、STIはクラスの継承でしかなく、クラスの継承というものの利点の一つにポリモーフィズムが含まれています。つまりは、上記の例のように、STIとポリモーフィック関連を一緒に使ってしまうと、役割が重複してしまうのです。上記の例だと、ポリモーフィズムの最終的な目標は以下のように、 user
が 果たして admin
であろうが normal_user
であろうがメソッド呼び出し時に気にせずにメソッドが使えるということです。これはポリモーフィック関連だろうが、STIであろうが実現可能です。
def open_image(user)
user.image.open
end
open_image(admin_user)
open_image(normal_user)
どっちを使ってもいいのか
いえ、そうではありません。あくまで、STIはクラスの継承なので、ポリモーフィズムを含むであって、他にも素敵なオブジェクティブ指向的なものが実現されます。なので、どちらも使用可能な時はSTIを使うべきです。
どっちも使うときはないのか
あります。例えば、今回の例で行くと、 User
とは全く関係ないモデルが has_many :images
の関係だとすれば、どちらも使います。ただ、これは、User
と他のモデルなので、STIと一緒に使えるとが言えないかもしれませんが・・・