使用ActiveModelSerializers为Rails JSON API创建嵌套关系

时间:2018-03-15 01:09:19

标签: ruby-on-rails active-model-serializers

我尝试使用以下JSON结构构建Rails API:

{ team: "team_name",
  players: players: [
    {
      name: "player_one",
      contracts: [
        {
          start_date: '7/1/2017',
          seasons: [
            {
              year: 2017,
              salary: 1000000
            }
          ]
        }
      ]
    },
    {
      name: "player_two"
    }
  ]
}

我的模型设置如下:

class Team < ApplicationRecord
  has_many :players
end

class Player < ApplicationRecord
  belongs_to :team
  has_many :contracts
end

class Contract < ApplicationRecord
  belongs_to :player
  has_many :seasons
end

class Season < ApplicationRecord
  belongs_to :contract
end

我目前正在使用以下代码,但我想使用ActiveModel Serializers(或其他干净的解决方案)来清理它

def show
  @team = Team.find(params[:id])
  render json: @team.as_json(
    except: [:id, :created_at, :updated_at],
    include: {
      players: {
        except: [:created_at, :updated_at, :team_id],
        include: {
          contracts: {
            except: [:id, :created_at, :updated_at, :player_id],
            include: {
              seasons: {
              except: [:id, :contract_id, :created_at, :updated_at]
              }
            }
          }
        }
      }
    }
  )
end

此外,数组项目按ID降序显示,我希望将其反转。我也希望通过第一个合同,第一季,薪水来命令球员。

2 个答案:

答案 0 :(得分:0)

我认为你的做法是正确的。看起来很干净。 您也可以在模型上使用named_scopes

请在此处查看docs

答案 1 :(得分:0)

Active Model Serializers 是一个很好的宝石,可以满足您的需求。假设你使用0-10-stable分支(最新:0.10.7),你可以这样:

序列化程序(Doc

# app/serializers/team_serializer.rb or app/serializers/api/v1/team_serializer.rb (if your controllers are in app/controllers/api/v1/ subdirectory)
class TeamSerializer < ActiveModel::Serializer
  attributes :name # list all desired attributes here
  has_many :players
end

# app/serializers/player_serializer.rb
class PlayerSerializer < ActiveModel::Serializer
  attributes :name # list all desired attributes here
  has_many :contracts
end

# app/serializers/contract_serializer.rb
class ContractSerializer < ActiveModel::Serializer
  attributes :start_date # list all desired attributes here
  has_many :seasons
end

# app/serializers/season_serializer.rb
class SeasonSerializer < ActiveModel::Serializer
  attributes :year, :salary # list all desired attributes here
end

TeamController

def show
  @team = Team
    .preload(players: [contracts: :seasons])
    .find(params[:id])

  render json: @team, 
    include: ['players.contracts.seasons'], 
    adapter: :attributes
end

注1:使用preload(或includes)可以帮助您eager-load multiple associations,从而避免 N + 1问题

注意2:您可能希望从Doc

中阅读include方法中render选项的详细信息