Techioz Blog

多態性関連に基づいて並べ替える

概要

次の多態性関係があるとします。

class Metric < ApplicationRecord
    belongs_to :metrizable, polymorphic: true
    belongs_to :company, class_name: 'Company', foreign_key: 'metrizable_id', optional: true
    belongs_to :portfolio, class_name: 'Portfolio', foreign_key: 'metrizable_id', optional: true

end
class Company < ApplicationRecord
    has_many :metrics, as: :metrizable, dependent: :destroy
end
class Portfolio < ApplicationRecord
    has_many :metrics, as: :metrizable, dependent: :destroy
end

メトリクスは会社またはポートフォリオのいずれかで測定できるようになりました。 両方のテーブル (会社、ポートフォリオ) のデータベースに名前フィールドがあります。

example:

@search = Metric.ransack(params[:q])
@search.sorts = ["company_name asc", "portfolio_name asc"]
@search.result.to_sql

次のようなものが得られます

"SELECT \"metrics\".* FROM \"metrics\" LEFT OUTER JOIN \"company\" ON \"company\".\"id\" = \"metrics\".\"metrizable_id\" LEFT OUTER JOIN \"portfolios\" ON \"portfolios\".\"id\" = \"metrics\".\"metrizable_id\" ORDER BY \"company\".\"name\" ASC, \"portfolios\".\"name\" ASC, \"metrics\".\"name\" ASC"

すべてのレコードを取得した場合でも、entity.name、entity(company,portfolio) で並べ替えられません。ソーステーブルとは関係なく、すべてをentity.nameで並べ替えたいと考えています。

解決策

データセットが小さく、それ以上のデータセットが期待されない場合は、単純に Ruby で並べ替えることができます。

それ以外の場合は、企業とポートフォリオのテーブルにデータベース ビューを追加し、それによって並べ替えることができます。たとえば、Postgres では次のようになります。

CREATE VIEW entities AS SELECT
  id,
  name,
  metrizable_id,
  'company' AS type
FROM
  companies
UNION
SELECT
  id,
  name,
  metrizable_id,
  'portfolio' AS type
FROM
  portfolios

エンティティモデル:

class Entity < ApplicationRecord
  self.inheritance_column = nil

  has_many :metrics
end

メトリクスモデル:

class Metric < ApplicationRecord
  # ...
  belongs_to :entity, foreign_key: 'metrizable_id', optional: true
end

そしてクエリ内では次のようになります。

@search = Metric.ransack(params[:q])
@search.sorts = ["entity_name asc"]
@search.result.to_sql