You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rails中使用PgSearch多搜索返回完整模型对象?

Rails中使用PgSearch multisearch返回完整模型对象的解决方案

问题描述

我在Rails中使用PgSearch的multisearch功能做搜索,目前只能返回content、searchable_type和searchable_id这几个字段,但我需要返回User和Blog模型的完整对象,期望的返回格式如下:

"data": [
  {
    "id": 2,
    "searchable_type": "User",
    "email": "abc",
    "first_name": "abc",
    "last_name": "xyz",
    "created_at": "2022-08-05T09:40:18.986Z",
    "updated_at": "2022-08-05T09:40:18.986Z"
  },
  {
    "id": 3,
    "searchable_type": "Blog",
    "title": "user",
    "created_at": "2022-08-05T09:40:18.986Z",
    "updated_at": "2022-08-05T09:40:18.986Z"
  }
]

我的现有代码如下:

Search控制器

class Api::V1::SearchController < Api::V1::ApiController
  def index
    @query = params[:value]
    @results = PgSearch.multisearch(@query)
    render json: { data: @results}, status: :ok
  end
end

Blog模型

class Blog < ApplicationRecord
 include PgSearch::Model
 multisearchable against: [:id, :title, :created_at, :updated_at ]
end

User模型

class User < ApplicationRecord
  include PgSearch::Model
  multisearchable against: [:id, :email, :first_name, :last_name ]
end

解决步骤

1. 获取关联的原始模型对象

PgSearch的multisearch返回的是PgSearch::Document实例,每个实例都通过searchable关联指向对应的User或Blog对象。你需要把这些文档转换成对应的模型实例,同时注意避免N+1查询问题:

修改Search控制器的index方法:

class Api::V1::SearchController < Api::V1::ApiController
  def index
    @query = params[:value]
    # 预加载关联对象,避免多次查询数据库
    @documents = PgSearch.multisearch(@query).includes(:searchable)
    # 提取对应的模型实例,compact过滤掉已删除的无效对象
    @results = @documents.map(&:searchable).compact
    render json: { data: @results }, status: :ok
  end
end

2. 自定义JSON返回格式(可选)

如果需要严格匹配你期望的格式(比如统一添加searchable_type字段、排除敏感字段),可以用以下两种方式处理:

方式一:用as_json直接自定义

修改控制器的render逻辑:

formatted_results = @results.map do |item|
  # 排除User模型的敏感字段,比如password_digest
  base_attrs = item.is_a?(User) ? item.as_json(except: [:password_digest]) : item.as_json
  base_attrs.merge(searchable_type: item.class.name)
end
render json: { data: formatted_results }, status: :ok

方式二:用序列化器(推荐复杂场景)

如果需要复用格式或者字段较多,可以生成对应的序列化器:

rails generate serializer User
rails generate serializer Blog

然后分别定义序列化器字段:

# app/serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
  attributes :id, :email, :first_name, :last_name, :created_at, :updated_at
  # 自定义添加searchable_type字段
  attribute :searchable_type do
    'User'
  end
end
# app/serializers/blog_serializer.rb
class BlogSerializer < ActiveModel::Serializer
  attributes :id, :title, :created_at, :updated_at
  attribute :searchable_type do
    'Blog'
  end
end

最后在控制器里使用序列化器:

render json: { data: @results }, each_serializer: ->(item) {
  "#{item.class.name}Serializer".constantize
}, status: :ok

内容的提问来源于stack exchange,提问作者awais iqbal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:15:36