为 Rails Restful API 返回不同类型的资源

问题描述

我正在根据客户端发送的 json 请求使用 ruby​​ 实现搜索端点,该请求的格式应为 GET /workspace/:id/searches? filter[query]=Old&filter[type]=ct:Tag,User,WokringArea&items=5 控制器看起来像这样

class SearchesController < ApiV3Controller
    load_and_authorize_resource :workspace,class: "Company"
    load_and_authorize_resource :user,through: :workspace
    load_and_authorize_resource :working_area,through: :workspace

    def index
      keyword = filtered_params[:query].delete("\000")
      keyword = '%' + keyword + '%'
      if filtered_params[:type].include?('User')
        @users = @workspace.users.where("LOWER(username) LIKE LOWER(?)",keyword)
      end
      if filtered_params[:type].include?('WorkingArea')
        @working_areas = @workspace.working_areas.where("LOWER(name) LIKE LOWER(?)",keyword)
      end
      @resources = @working_areas

      respond_json(@resources)
    end

    private

    def filtered_params
      params.require(:filter).permit(:query,:type)
    end

    def ability_klasses
      [WorkspaceAbility,UserWorkspaceAbility,WorkingAreaAbility]
    end
  end

respond_json 以 json 格式返回资源,它看起来像这样

def respond_json(records,status = :ok)
if records.try(:errors).present?
  render json: {
    errors: records.errors.map do |pointer,error|
      {
        status: :unprocessable_entity,source: { pointer: pointer },title: error
      }
    end
  },status: :unprocessable_entity
  return
elsif records.respond_to?(:to_ary)
  @pagy,records = pagy(records)
end

options = {
  include: params[:include],permissions: permissions,current_ability: current_ability,Meta: Meta_infos
}

render json: ApplicationRecord.serialize_fast_apijson(records,options),status: status

结束

现在的问题是响应应该是这样的:

{
data: [
    {
        id: 32112,type: 'WorkingArea'
        attributes: {}
    },{
        id: 33321,type: 'User',attributes: {}
    },{
        id: 33221,type: 'Tag'
        attributes: {}
    }

如何让我的代码支持响应具有不同类型的资源?

解决方法

您可以根据 API 的结果定义一个模型,而不是在您的数据库中。然后包含一些 ActiveModel 模块以获得更多功能。

# app/models/workspace_result.rb
class WorkspaceResult
  include ActiveModel::Model
  include ActiveModel::Validations
  include ActiveModel::Serialization

  attr_accessor(
    :id,:type,:attributes
  )

  def initialize(attributes={})
    filtered_attributes = attributes.select { |k,v| self.class.attribute_method?(k.to_sym) }
    super(filtered_attributes)
  end

  def self.from_json(json)
    attrs = JSON.parse(json).deep_transform_keys { |k| k.to_s.underscore }
    self.new(attrs)
  end
end

然后在您的 API 结果中,您可以执行以下操作:

results = []
response.body["data"].each do |result|
  results << WorkspaceArea.from_json(result)
end

你也可以在这个模型上定义实例方法,等等。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...