多態性関連に基づいて並べ替える
概要
次の多態性関係があるとします。
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