多态关联排序问题:如何统一按关联实体name排序?
解决Rails多态关联下Ransack统一排序关联实体name的问题
核心思路
多态关联中Metric仅会关联Company或Portfolio其中一个实体,因此可以通过SQL条件判断逻辑,将两个关联表的name字段合并为一个虚拟字段,基于该字段实现统一排序。
具体实现步骤
1. 在Metric模型中自定义Ransack排序字段
通过Ransack提供的ransacker方法,创建名为metrizable_name的虚拟排序字段,根据metrizable_type判断取对应关联表的name值:
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 # 自定义Ransack排序字段,匹配对应关联实体的name ransacker :metrizable_name do Arel.sql("CASE WHEN metrics.metrizable_type = 'Company' THEN companies.name ELSE portfolios.name END") end end
2. 调整Ransack查询逻辑
直接使用自定义的metrizable_name字段进行排序,无需同时指定两个关联表的name:
@search = Metric.ransack(params[:q]) @search.sorts = ["metrizable_name asc"] # 统一按关联实体的name字段排序 @metrics = @search.result.includes(:metrizable) # 预加载关联实体避免N+1查询
3. 数据库适配说明(可选)
不同数据库的条件语法略有差异,可根据实际使用的数据库调整:
- MySQL/MariaDB可替换为
IF(metrics.metrizable_type = 'Company', companies.name, portfolios.name) - PostgreSQL可使用
COALESCE(companies.name, portfolios.name)(因每个Metric仅关联一个实体,另一表的name必然为NULL,COALESCE会自动取非NULL值)
内容的提问来源于stack exchange,提问作者Hernan Acosta
相关产品推荐
相关产品推荐

