首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Rails:使用active_model_serializers序列化深度嵌套的关联

Rails:使用active_model_serializers序列化深度嵌套的关联
EN

Stack Overflow用户
提问于 2015-08-19 02:20:00
回答 7查看 34.9K关注 0票数 41

我使用的是Rails 4.2.1active_model_serializers 0.10.0.rc2

我是API的新手,选择active_model_serializers是因为它似乎正在成为rails的标准(尽管我并不反对使用RABL或其他序列化程序)。

我遇到的问题是,我似乎不能在多级关系中包含各种属性。例如,我有:

Projects

代码语言:javascript
复制
class ProjectSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name,
                                  :updated_at

  has_many                        :estimates, include_nested_associations: true

end

估计

代码语言:javascript
复制
class EstimateSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :release_version, 
                                  :exchange_rate, 
                                  :updated_at,

                                  :project_id, 
                                  :project_code_id, 
                                  :tax_type_id 

  belongs_to                      :project
  belongs_to                      :project_code
  belongs_to                      :tax_type

  has_many                        :proposals

end

Proposals

代码语言:javascript
复制
class ProposalSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :updated_at,

                                  :estimate_id

  belongs_to                      :estimate
end

当我点击/projects/1时,上面的代码会产生:

代码语言:javascript
复制
{
  "id": 1,
  "name": "123 Park Ave.",
  "updated_at": "2015-08-09T02:36:23.950Z",
  "estimates": [
    {
      "id": 1,
      "name": "E1",
      "release_version": "v1.0",
      "exchange_rate": "0.0",
      "updated_at": "2015-08-12T04:23:38.183Z",
      "project_id": 1,
      "project_code_id": 8,
      "tax_type_id": 1
    }
  ]
}

然而,我希望它产生的是:

代码语言:javascript
复制
{
  "id": 1,
  "name": "123 Park Ave.",
  "updated_at": "2015-08-09T02:36:23.950Z",
  "estimates": [
    {
      "id": 1,
      "name": "E1",
      "release_version": "v1.0",
      "exchange_rate": "0.0",
      "updated_at": "2015-08-12T04:23:38.183Z",
      "project": { 
        "id": 1,
        "name": "123 Park Ave."
      },
      "project_code": {
        "id": 8,
        "valuation": 30
      },
      "tax_type": {
        "id": 1,
        "name": "no-tax"
      },
      "proposals": [
        {
          "id": 1,
          "name": "P1",
          "updated_at": "2015-08-12T04:23:38.183Z"
        },
        {
          "id": 2,
          "name": "P2",
          "updated_at": "2015-10-12T04:23:38.183Z"
        }
      ]
    }
  ]
}

理想情况下,我还希望能够指定哪些属性、关联和这些关联的属性包含在每个序列化程序中。

我一直在研究AMS的问题,似乎确实有一些关于应该如何处理的问题(或者这种功能是否实际上被支持),但我很难弄清楚当前的状态到底是什么。

建议的解决方案之一是用调用嵌套属性的方法覆盖属性,但这似乎被认为是一种黑客行为,所以如果可能的话,我想避免这种情况。

无论如何,如果您能举例说明如何处理此问题或一般的API建议,我们将不胜感激。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2015-08-20 08:54:56

所以这可能不是最好的,甚至不是一个好的答案,但这是我需要的工作方式。

虽然在使用带有AMS的json_api适配器时似乎支持包含嵌套和侧边加载的属性,但我需要支持flat json。此外,这个方法工作得很好,因为每个序列化程序都专门生成我需要的东西,独立于任何其他序列化程序,而不需要在控制器中做任何事情。

注释/替代方法总是受欢迎的。

项目模型

代码语言:javascript
复制
class Project < ActiveRecord::Base      
  has_many  :estimates, autosave: true, dependent: :destroy
end

ProjectsController

代码语言:javascript
复制
def index
  @projects = Project.all
  render json: @projects
end

ProjectSerializer

代码语言:javascript
复制
class ProjectSerializer < ActiveModel::Serializer
  attributes  :id, 
              :name,
              :updated_at,

              # has_many
              :estimates



  def estimates
    customized_estimates = []

    object.estimates.each do |estimate|
      # Assign object attributes (returns a hash)
      # ===========================================================
      custom_estimate = estimate.attributes


      # Custom nested and side-loaded attributes
      # ===========================================================
      # belongs_to
      custom_estimate[:project] = estimate.project.slice(:id, :name) # get only :id and :name for the project
      custom_estimate[:project_code] = estimate.project_code
      custom_estimate[:tax_type] = estimate.tax_type

      # has_many w/only specified attributes
      custom_estimate[:proposals] = estimate.proposals.collect{|proposal| proposal.slice(:id, :name, :updated_at)}

      # ===========================================================
      customized_estimates.push(custom_estimate)
    end

    return customized_estimates
  end
end

结果

代码语言:javascript
复制
[
  {
    "id": 1,
    "name": "123 Park Ave.",
    "updated_at": "2015-08-09T02:36:23.950Z",
    "estimates": [
      {
        "id": 1,
        "name": "E1",
        "release_version": "v1.0",
        "exchange_rate": "0.0",
        "created_at": "2015-08-12T04:23:38.183Z",
        "updated_at": "2015-08-12T04:23:38.183Z",
        "project": {
          "id": 1,
          "name": "123 Park Ave."
        },
        "project_code": {
          "id": 8,
          "valuation": 30,
          "created_at": "2015-08-09T18:02:42.079Z",
          "updated_at": "2015-08-09T18:02:42.079Z"
        },
        "tax_type": {
          "id": 1,
          "name": "No Tax",
          "created_at": "2015-08-09T18:02:42.079Z",
          "updated_at": "2015-08-09T18:02:42.079Z"
        },
        "proposals": [
          {
            "id": 1,
            "name": "P1",
            "updated_at": "2015-08-12T04:23:38.183Z"
          },
          {
            "id": 2,
            "name": "P2",
            "updated_at": "2015-10-12T04:23:38.183Z"
          }
        ]
      }
    ]
  }
]

我基本上忽略了在序列化程序中实现任何has_manybelongs_to关联的尝试,而只是定制了行为。我使用slice来选择特定的属性。希望一个更优雅的解决方案会出现。

票数 16
EN

Stack Overflow用户

发布于 2016-07-02 14:37:03

Per commit 1426:https://github.com/rails-api/active_model_serializers/pull/1426 -和相关讨论,您可以看到jsonattributes序列化的默认嵌套是一个级别。

如果默认情况下需要深度嵌套,可以在active_model_serializer初始值设定项中设置配置属性:

ActiveModelSerializers.config.default_includes = '**'

有关v0.10.6的详细参考,请访问:https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/adapters.md#include-option

票数 58
EN

Stack Overflow用户

发布于 2015-09-01 04:28:09

如果您使用的是JSONAPI适配器,则可以执行以下操作来呈现嵌套关系:

代码语言:javascript
复制
render json: @project, include: ['estimates', 'estimates.project_code', 'estimates.tax_type', 'estimates.proposals']

您可以从jsonapi文档中阅读更多内容:http://jsonapi.org/format/#fetching-includes

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32079897

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档