Rails:使用 active_model_serializers 序列化深度嵌套的关联 [英] Rails: Serializing deeply nested associations with active_model_serializers

查看:44
本文介绍了Rails:使用 active_model_serializers 序列化深度嵌套的关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Rails 4.2.1active_model_serializers 0.10.0.rc2

我是 API 的新手并选择了 active_model_serializers 因为它似乎正在成为 Rails 的标准(虽然我不反对使用 RABL 或其他序列化程序)

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

项目

class ProjectSerializer 

估计

class EstimateSerializer 

提案

class ProposalSerializer 

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

<代码>{id":1,名称":123 Park Ave.",updated_at":2015-08-09T02:36:23.950Z",估计":[{id":1,名称":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}]}

但是,我希望它产生的是:

<代码>{id":1,名称":123 Park Ave.",updated_at":2015-08-09T02:36:23.950Z",估计":[{id":1,名称":E1",release_version":v1.0",exchange_rate":0.0",updated_at":2015-08-12T04:23:38.183Z",项目":{id":1,名称":123 Park Ave."},项目代码":{id":8,估值":30},税类型":{id":1,名称":无税";},提案":[{id":1,名称":P1",updated_at":2015-08-12T04:23:38.183Z"},{id":2,名称":P2",updated_at":2015-10-12T04:23:38.183Z"}]}]}

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

我一直在查看 AMS 问题,似乎在如何处理此问题(或者是否实际上支持这种功能)方面存在一些反复,但我很难弄清楚到底当前状态是什么.

建议的解决方案之一是使用调用嵌套属性的方法覆盖该属性,但这似乎被视为一种黑客行为,因此我想尽可能避免它.

无论如何,我们将非常感谢您提供有关如何执行此操作或一般 API 建议的示例.

解决方案

所以这不是最好的答案,甚至不是一个好的答案,但这是我需要的方法.

虽然在将 json_api 适配器与 AMS 一起使用时似乎支持包含嵌套和侧载属性,但我需要支持平面 json.此外,这种方法运行良好,因为每个序列化器都专门生成我需要的内容,独立于任何其他序列化器,而无需在控制器中执行任何操作.

始终欢迎评论/替代方法.

项目模型

class 项目 <ActiveRecord::Basehas_many :estimates, autosave: true, 依赖: :destroy结尾

项目控制器

def 索引@projects = Project.all渲染 json:@projects结尾

ProjectSerializer

class ProjectSerializer 

结果

<预><代码>[{身份证":1,"name": "123 Park Ave.","updated_at": "2015-08-09T02:36:23.950Z",估计":[{身份证":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",项目": {身份证":1,"name": "123 Park Ave."},项目代码":{身份证":8,估值":30,"created_at": "2015-08-09T18:02:42.079Z","updated_at": "2015-08-09T18:02:42.079Z"},税类型":{身份证":1,"name": "无税","created_at": "2015-08-09T18:02:42.079Z","updated_at": "2015-08-09T18:02:42.079Z"},提案":[{身份证":1,"name": "P1","updated_at": "2015-08-12T04:23:38.183Z"},{身份证":2,"name": "P2","updated_at": "2015-10-12T04:23:38.183Z"}]}]}]

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

I'm using Rails 4.2.1 and active_model_serializers 0.10.0.rc2

I'm new to API's and chose active_model_serializers because it seems to be becoming the standard for rails (Although I'm not opposed to using RABL or another serializer)

The problem I'm having is that I can't seem to include various attributes in multi-level relationships. For instance, I have:

Projects

class ProjectSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name,
                                  :updated_at

  has_many                        :estimates, include_nested_associations: true

end

and Estimates

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

class ProposalSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :updated_at,

                                  :estimate_id

  belongs_to                      :estimate
end

When I hit the /projects/1 the above produces:

{
  "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
    }
  ]
}

However, what I'd like it to produce is:

{
  "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"
        }
      ]
    }
  ]
}

Ideally, I'd also like to be able to specify which attributes, associations, and attributes of those associations are included in each serializer.

I've been looking through the AMS issues, and there does seem to be some back and forth on how this should be handled (or if this kind of functionality is even actually supported) but I'm having difficulty figuring out exactly what the current state is.

One of the proposed solutions was to override the attribute with a method to call the nested attributes, but that seems to be regarded as a hack so I wanted to avoid it if possible.

Anyway, an example of what of how to go about this or general API advice would be much appreciated.

解决方案

So this my not be the best or even a good answer, but this is working how I need it to.

While including nested and side-loaded attributes appears to be supported when using the json_api adapter with AMS, I needed support for flat json. In addition, this method worked well because each serializer is specifically generating exactly what I need it to independent of any other serializer and without having to do anything in the controller.

Comments / alternate methods are always welcome.

Project Model

class Project < ActiveRecord::Base      
  has_many  :estimates, autosave: true, dependent: :destroy
end

ProjectsController

def index
  @projects = Project.all
  render json: @projects
end

ProjectSerializer

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

Result

[
  {
    "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"
          }
        ]
      }
    ]
  }
]

I basically disregarded trying to implement any has_many or belongs_to associations in the serializers and just customized the behavior. I used slice to select specific attributes. Hopefully a more elegant solution will be forth coming.

这篇关于Rails:使用 active_model_serializers 序列化深度嵌套的关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆