せらぴんブログ

サークル「せらぴん」のうのはな透です。やっぱり眼鏡っ娘が好き!!

polymorphicなモデルをjoinできるメソッドがほしい

RubyActiveRecordは、ポリモーフィック関連というクッッッソ便利な機能があります。
例えば「ブログの記事にタグを使いたいなー、あ、でもブログ自体にもタグを使いたいな―」といった場合に、TagモデルをEntryモデルでもBlogモデルでも使えるようにしちゃおう!という機能。

このポリモーフィック関連を使っていて、ふと以下のことがやりたくなる。
「Tagモデルの関連先が実在しなかった場合、それをdefault_scopeとかで取り除けると便利なんだけどなぁ……」

とりあえずざっと調べたけど、ポリモーフィックは関連先が複数あるのでリレーションでどうこうするのは難しそう。

Rails4: ActiveRecord polymorphicのjoins検索?(メモ) | プログラミング・ノート by smallmake

考えられる候補は、上記のようにSQLを直接発行するゴリ押しパターンか、SQL発行後に抽出しちゃうパターン。今回は後者で実装しちゃいます。

class Entry < ActiveRecord::Base
  has_many :tags, as :attachable
end

class Tag < ActiveRecord::Base
  belongs_to :attachable, polymorphic: true

  # 関連先のないものを省く。Relationではなく直接Arrayを返すので注意
  def self.living
    return all.select{|t| t.attachable.present? }
  end
end

# 特定の関連先に紐付いている、かつ生きているタグを取得
def get_living_tags(type)
  return Tag.where(attachable_type: type).living
end

ActiveRecordではリレーションの後にクラスメソッドをつなげてArrayなどの加工結果を得ることができます。クッッッソ便利なのでこれも積極的に使っていきましょう。ただ、リレーションのチェインが切れてしまうのが唯一の難点です。まぁ「SQLで行えそうにない処理をクラスメソッドで行う」という構造上しょうがないというか当たり前のことなんですがね!!

ポリモーフィックの関連先をjoinするSQLを動的に作ってくれる」ような夢のシステムがあったらいいけど、多分実現するの死ぬほど面倒臭いだろうなぁ。