6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tips: Railsでポリモーフィック関連付けを使うときはインターフェースに依存した実装をするようにしよう

Last updated at Posted at 2023-11-30

この記事は何

Railsにはポリモーフィック関連付けという機能があります。

この機能は使い方によっては便利な一方、依存を複雑化させる原因にもなりうるものです。
この記事では、ポリモーフィック関連を使うときにやりがちな「特定のモデルへの依存」を避けるテクニックをご紹介します。

ポリモーフィック関連の具体的な使い方はドキュメントや、以下の記事などをご参考ください。

ポリモーフィック関連を使っている時に起こること

ポリモーフィック関連を使っていると、特定のモデルの場合にのみ実行したくなる処理などが生まれた時に、以下のような実装をしてしまうことがあります。

class Like < ApplicationRecord
  belongs_to :like_user, User
  belongs_to :liked_user, User
  belongs_to :item, polymorphic: true
  after_create :log_liked_data, if: :article?

  def log_liked_data
    item.track(user: like_user)
  end

  def article?
    item.is_a?(Article)
  end
end

class Article < ApplicationRecord
  has_many :likes, as: :item
end

class Question < ApplicationRecord
  has_many :likes, as: :item
end

このような実装は、正しくは動きますが、本来Like側では依存するべきではないArticleに依存した処理になってしまっており、依存関係が複雑化してしまっています。
このような実装はバグも生みやすくなり、できれば避けた方が良い実装です。

解決方法

このような問題を解決する方法は、SOLID原則でいう、いわゆる「インターフェース依存の原則」と「依存関係逆転の原則」を適用した実装にしていきます。

実装する流れは以下の通りです。

  • Likeもしくは同じネームスペース内に、moduleでインターフェースの定義を行う
  • ポリモーフィック関連で依存する側のモデルに、実装したインターフェースをincludeし、処理の実装を行う
  • Likeはmoduleで定義したインターフェースにのみ依存するように実装を変える

コードにすると以下の通りです。

class Like < ApplicationRecord
  belongs_to :like_user, User
  belongs_to :liked_user, User
  belongs_to :item, polymorphic: true
  after_create :create_side_effect

  def create_side_effect
    item.like_create_side_effect(like: self)
  end

  module Likable
    extend ActiveSupport::Concern
    
    included do
      has_many :likes, as: :item
    end

    def like_create_side_effect(like:)
      raise NotImplementedError
    end
  end
end

class Article < ApplicationRecord
  include Like::Likable

  concerning :Likable do
    def like_create_side_effect(like:)
      Tracker.track(user: like.like_user, target: self)
    end
  end
end

class Question < ApplicationRecord
  include Like::Likable

  concerning :Likable do
    def like_create_side_effect(like:); end
  end
end

まとめ

ポリモーフィック関連は、依存先を抽象化するテクニックです。
抽象化する場合は、特定のモデルに依存するような処理は基本的に書かずに、インターフェースに依存するような実装をするようにしましょう。

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?