Rails 4渲染json有多个对象并包含

问题描述 投票:0回答:1

我有一个Rails 4 API。当用户在视图中搜索船只时,执行此方法会使所有船只与搜索过滤器匹配并使用渲染ActiveModel返回一个船模型数组作为json,并且:include和:仅限这样:

render :json => @boats, :include => { :mainPhoto => {:only => [:name, :mime]},
                                      :year => {:only => :name},
                                      # other includes...}

这很有效。

但是,除了这些信息,在视图中,我想显示船只的总数,例如“显示80艘船中的1至20艘”,因为有一个分页功能。所以,重点是我需要提供80艘船。我想避免发送两个执行几乎相同逻辑的请求,因此想法只运行一次searchBoats方法,并在结果中提供船只列表和变量numTotalBoats中的船只总数。我知道numTotalBoats不是船模型属性。所以,我认为它应该在渲染结果中包含一个自变量。就像是:

render :json => {boats: @boats with all the includes, numTotalBoats: @NumTotalBoats}

我尝试了数以千计的组合,但是我得到了语法错误,或者没有一个会返回预期的结果,例如

{boats: [boat1 with all the includes, boat2 with all the includes, ... boatN with all the includes], numTotalBoats: N}
ruby-on-rails json
1个回答
1
投票

没有添加任何宝石:

def index
  boats = Boat.includes(:year)

  render json: {
    boats: boats.as_json(include: { year: { only: :name } }),
    numTotalBoats: boats.count
  }
end

但在某些时候,我相信你应该使用独立的序列化器:

注意:根据您是否使用分页gem,您可能需要将下面的.count调用更改为.total_count(对于Kaminari)或其他将从分页集合中正确读取计数的内容。

我建议使用ActiveModel Serializers,这就是你的情况如何实现。

首先将gem添加到Gemfile:

gem 'active_model_serializers', '~-> 0.10'

在config / initializers / active_model_serializer.rb中覆盖适配器:

ActiveModelSerializers.config.adapter = :json

为您的模型定义序列化程序,

# app/serializers/boat_serializer.rb
class BoatSerializer < ActiveModel::Serializer
  attributes :name

  has_one :year
end

# app/serializers/year_serializer.rb
class YearSerializer < ActiveModel::Serializer
  attributes :name
end

最后,在你的控制器中:

boats = Boat.includes(:year)

render json: boats, meta: boats.count, meta_key: "numTotalBoats"

你会实现:

{
  "boats": [
    {
      "name": "Boaty McBoatFace",
      "year": {
        "name": "2018"
      }
    },
    {
      "name": "Titanic",
      "year": {
        "name": "1911"
      }
    }
  ],
  "numTotalBoats": 2
}

在每个索引控制器中添加该计数有点单调乏味,因此我通常最终定义自己的适配器或集合序列化程序,以便自动处理(使用Rails 5测试,而不是4)。

# lib/active_model_serializers/adapter/json_extended.rb
module ActiveModelSerializers
  module Adapter
    class JsonExtended < Json
      def meta
        if serializer.object.is_a?(ActiveRecord::Relation)
          { total_count: serializer.object.count }
        end.to_h.merge(instance_options.fetch(:meta, {})).presence
      end
    end
  end
end

# config/initializers/active_model_serializer.rb
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonExtended

# make sure to add lib to eager load paths
# config/application.rb
config.eager_load_paths << Rails.root.join("lib")

现在您的索引操作可能如下所示

def index
  boats = Boat.includes(:year)

  render json: boats
end

并输出:

{
  "boats": [
    {
      "name": "Boaty McBoatFace",
      "year": {
        "name": "2018"
      }
    },
    {
      "name": "Titanic",
      "year": {
        "name": "1911"
      }
    }
  ],
  "meta": {
    "total_count": 2
  }
}

我认为为不同的端点解析这个计数要容易一些,并且在使用集合进行响应时会自动获取它,因此您的控制器会更简单一些。

© www.soinside.com 2019 - 2024. All rights reserved.