【问题标题】:Active Model Serializers -- Customizing JSON responseActive Model Serializers -- 自定义 JSON 响应
【发布时间】:2016-06-08 23:24:30
【问题描述】:

在这里快速提问。尝试搜索无济于事。

我正在努力为我当前的项目开发一个 RESTful API。我发现 Rails 绝对是这个用途的宠儿,所以再来看看 rails 的厉害之处!

但是,我在为 /users 设计当前 API 响应时遇到了问题,该方法应该返回用户对象的 JSON 数组:

我的用户模型:

class User < ActiveRecord::Base

  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable

  has_many :favorites
  has_many :reservations

  has_many :venues, through: :favorites
  has_many :venues, through: :reservations

  belongs_to  :gender
  belongs_to  :city
  belongs_to  :role
  has_one  :avatar

  has_many :payments
  has_one  :payment_history

  has_many :promotion_claims
  has_many :social_identifiers

end

我的路线:

Rails.application.routes.draw do

  namespace :api, defaults: { format: :json } do
    namespace :v1 do
      devise_for :users

      ..........................

      resources :roles
      resources :genders
      resources :cities

      #Users method
      get 'users', to: "users#index"

    end
  end

我的控制器:

class API::V1::UsersController < API::V1::ApplicationController
  before_action :set_address, only: [:show, :edit, :update, :destroy]

  # GET /users
  # GET /users.json
  def index
    @users = User.all
    render json: @users
  end
end

我的序列化器:

class UserSerializer < ActiveModel::Serializer
  attributes :id, :first_name, :last_name, :cellphone, :email, :birthday, :username
  has_one :gender
  has_one :city
  has_one :role
end

class GenderSerializer < ActiveModel::Serializer
  attributes :name
end

class CitySerializer < ActiveModel::Serializer
  attributes :name
end

class RoleSerializer < ActiveModel::Serializer
  attributes :name
end

就我得到的 json 响应而言,这实现了非常令人满意的结果:

// GET http://localhost:3000/api/v1/users

[
  {
    "id": 1,
    "first_name": "Richmond",
    "last_name": "Huels",
    "cellphone": "29 8244 9100",
    "email": "coy.muller@medhurst.us",
    "birthday": "2011-02-23T19:24:00.151Z",
    "username": "alba.ortiz",
    "gender": {
      "name": "Male"
    },
    "city": {
      "name": "San Pedro Garza García"
    },
    "role": {
      "name": "admin"
    }
  },

但是,我希望我的 JSON 响应更像:

// 20160225162402
// GET http://localhost:3000/api/v1/users

[
  {
    "id": 1,
    "first_name": "Richmond",
    "last_name": "Huels",
    "cellphone": "29 8244 9100",
    "email": "coy.muller@medhurst.us",
    "birthday": "2011-02-23T19:24:00.151Z",
    "username": "alba.ortiz",
    "gender": "Male",
    "city": "San Pedro Garza García",
    "role": "rp"
  },

我尝试覆盖 UserSerializer 中的 attributes 方法并使其实现,这样我就可以在返回它之前对 json 哈希做任何我想做的事情,但它不起作用:

  #attributes override to get the right format for the response
  def attributes
    data = super
    data[:city] = data[:city][:name]
    data[:gender] = data[:gender][:name]
    data[:role] = data[:city][:name]
    data
  end

有什么方法可以实现我的 API 所需吗?

感谢红宝石学家,你们统治并一直保持着惊人的水平!

【问题讨论】:

    标签: ruby-on-rails json api rest active-model-serializers


    【解决方案1】:

    我想通了:

    我觉得这是一种 hacky 方法,因为基本上,我没有为与我的 User 模型相关的模型使用序列化程序,并且我正在覆盖 attributes 方法,但我所做的是我删除了所有关系我的用户序列化器然后我完全按照我之前写的那样覆盖属性:

    class UserSerializer < ActiveModel::Serializer
      attributes :id, :first_name, :last_name, :gender, :cellphone, :city, :email, :birthday, :username, :role
    
      def attributes
        data = super
        data[:gender] = data[:gender][:name]
        data[:city] = data[:city][:name]
        data[:role] = data[:role][:name]
        data
      end
    end
    

    这让我得到了我非常需要的 JSON 响应:

    编辑:我找到了一个更好的方法:

    我的序列化器:

    class UserSerializer < ActiveModel::Serializer
      attributes :id, :first_name, :last_name, :gender, :cellphone, :city, :email, :birthday, :username, :role
    
      def gender
        return object.gender.name
      end
    
      def city
        return object.city.name
      end
    
      def role
        return object.role.name
      end
    
    end
    

    在我看来,它更简洁、更面向对象。

    确保所有其他序列化程序都已到位,并且模型对其字段进行了适当的验证。

    结果一模一样:

    【讨论】:

    • 谢谢。不确定我是否同意 Rails 是天赐之物,有时它过于声明性不利于自身的利益,但它很好。
    【解决方案2】:

    如果要将结果合并为单个哈希。

    你可以使用flatten方法,例如。

    s = [ 1, 2, 3 ]           #=> [1, 2, 3]
    t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
    a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
    a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    在你的情况下,在获得所有结果并将其传递给变量“data

    data.flatten
    

    【讨论】:

      猜你喜欢
      • 2017-05-19
      • 1970-01-01
      • 2016-08-09
      • 2017-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多