Serializing deeply nested associations with active_model_serializers

前端 未结 6 1651
無奈伤痛
無奈伤痛 2020-12-08 06:37

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 i

6条回答
  •  北荒
    北荒 (楼主)
    2020-12-08 07:33

    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.

提交回复
热议问题