Ruby on rails Rails 4使用多个对象呈现json,包括

Ruby on rails Rails 4使用多个对象呈现json,包括,ruby-on-rails,json,Ruby On Rails,Json,我有一个Rails4API。当用户在视图中搜索船只时,将执行此方法,获取与搜索过滤器匹配的所有船只,并使用render ActiveModel和:include and:only将船只模型数组返回为json,如下所示: render :json => @boats, :include => { :mainPhoto => {:only => [:name, :mime]}, :year =>

我有一个Rails4API。当用户在视图中搜索船只时,将执行此方法,获取与搜索过滤器匹配的所有船只,并使用render ActiveModel和:include and:only将船只模型数组返回为json,如下所示:

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}

不添加任何宝石:

def index
  boats = Boat.includes(:year)

  render json: {
    boats: boats.as_json(include: { year: { only: :name } }),
    numTotalBoats: boats.count
  }
end
不过,在某些情况下,我认为您应该使用独立序列化程序:

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

我建议使用,这是如何为您的案例完成的

首先将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": [
    {
      "name": "Boaty McBoatFace",
      "year": {
        "name": "2018"
      }
    },
    {
      "name": "Titanic",
      "year": {
        "name": "1911"
      }
    }
  ],
  "numTotalBoats": 2
}
在每个索引控制器中添加该计数有点单调乏味,因此我通常最终定义自己的适配器或集合序列化程序,以便自动完成这项工作(使用Rails 5而不是4进行测试)

和输出:

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

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

无需添加任何gem:

def index
  boats = Boat.includes(:year)

  render json: {
    boats: boats.as_json(include: { year: { only: :name } }),
    numTotalBoats: boats.count
  }
end
不过,在某些情况下,我认为您应该使用独立序列化程序:

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

我建议使用,这是如何为您的案例完成的

首先将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": [
    {
      "name": "Boaty McBoatFace",
      "year": {
        "name": "2018"
      }
    },
    {
      "name": "Titanic",
      "year": {
        "name": "1911"
      }
    }
  ],
  "numTotalBoats": 2
}
在每个索引控制器中添加该计数有点单调乏味,因此我通常最终定义自己的适配器或集合序列化程序,以便自动完成这项工作(使用Rails 5而不是4进行测试)

和输出:

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


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

您尝试过这样做吗
render:json=>{boats:@boats,numTotalBoats:@boats.size}
您的意思是说您正在使用
active\u model\u序列化程序
gem?AMS可以用作PORO,这意味着您可以事先获取可序列化对象,然后将其传递给
render
方法。你可以从AMS文件中找到这个想法,我不这么认为。我没有安装gem。只是ror提供的默认活动模型。什么是
numTotalBoats:
?它是一个模型还是一个方法?它不是一个模型,它只是一个变量,我需要传递所有船只的计数。你试过这样吗
render:json=>{boats:@boats,numTotalBoats:@boats.size}
您的意思是说您正在使用
active\u model\u序列化程序
gem?AMS可以用作PORO,这意味着您可以事先获取可序列化对象,然后将其传递给
render
方法。你可以从AMS文件中找到这个想法,我不这么认为。我没有安装gem。只是ror提供的默认活动模型。什么是
numTotalBoats:
?它是一个模型还是一个方法?它不是一个模型,它只是一个变量,我需要传递所有船只的计数。谢谢!看起来不错。关于你的最后一句话。你的意思是在两个不同的端点中保持搜索船的逻辑和计数分离,即使需要运行的查询相同,并且一个答案包含船只集合,另一个包含计数?使用一个端点。我的意思是保持count键独立于模型名,因此如果您有更多端点,您可以简单地引用
count
,而不是
numTotalBoats
numTotalYears
,等等。关于扩展适配器,如果您有3个索引操作,您需要在所有这些操作中显式地提供这些元键,这是大量的重复,应该干涸。@Rober我在开始时添加了一个不需要任何宝石的答案。谢谢。让我检查一下。我试过了,但我想不止两次,它会做出奇怪的事情。但是,让我检查一下,然后再给你回复!你的回答是对的!这就是我一直在寻找的答案。这是我尝试过的方法,但由于某种原因,我的语法错误,无法正确解析。现在它工作了。谢谢!看起来不错。关于你的最后一句话。你的意思是在两个不同的端点中保持搜索船的逻辑和计数分离,即使需要运行的查询相同,并且一个答案包含船只集合,另一个包含计数?使用一个端点。我的意思是保持count键独立于模型名称,因此如果有更多端点,您只需参考
count
,而不是
numTotalBoats