Как переопределить корневой ключ в полезной нагрузке ответа Grape API?

module Entities
  class StuffEntity < Grape::Entity
    root 'stuffs', 'stuff'
    ...

Как я могу высушить свой код, повторно используя этот объект, сохраняя при этом возможность переименовывать корневые ключи («вещи» и «вещи»), определенные в сущности?

Мне может понадобиться сделать это в сценарии, где я выставляю подмножество коллекции, представленной существующей сущностью, или выставляю связанную коллекцию, которая может быть представлена ​​существующей сущностью.


person Allison    schedule 03.09.2020    source источник


Ответы (1)


Скрытие корневого ключа при раскрытии связанного объекта или коллекции

Допустим, у меня есть объект с атрибутом name и некоторая коллекция scoped_stuff, которую я хочу представить как some_stuffs. Я мог бы сделать это с таким объектом:

module Entities
  class CoolStuffEntity < Grape::Entity
    root 'cool_stuffs', 'cool_stuff'
    
    expose :some_stuffs, documentation: {
      type: Entities::StuffEntity
    } do |object, _options|
      Entities::StuffEntity.represent(
        object.class.scoped_stuff,
        root: false
      )
    end
    
    expose :name, documentation: { type: 'string' }
  end
end

Передача root: false методу represent гарантирует, что вложенная ассоциация будет представлена ​​без корневого ключа. Вот как выглядят представления с этим аргументом и без него:

# Without root: false
cool_stuff: {
  some_stuffs: { 
    stuffs:    [ /* collection represented by StuffEntity */ ] 
  },
  name: 'Something'
}

# With root: false
cool_stuff: { 
  some_stuffs: [ /* collection represented by StuffEntity */ ],
  name:        'Something'
}

В этом случае передача root: false гарантирует, что корневой ключ вложенной сущности не будет включен в наше представление.

Установка имени корневого ключа при представлении объекта без определенного корня

Допустим, у нас есть эта сущность, где мы не указали корень:

module Entities
  class StuffEntity < Grape::Entity
    expose :name, documentation: { type: 'string' }
  end
end

Сериализуемый хеш для объекта, представленного этой сущностью, будет выглядеть так: { name: 'Object name' }

В нашем API мы можем указать ключ ответа следующим образом:

get do
  stuff_object = Stuff.find_by(user_id: current_user)

  present stuff_object, 
    with: Entities::StuffEntity,
    root: :stuff
end

Так что наш ответ будет выглядеть так: { stuff: { name: 'Object name' } }

Обратите внимание, что здесь 'root' принимает строковые и символьные аргументы.

Если вы хотите переименовать корневой ключ в своем ответе API

А что, если у меня есть объект, в котором я указал корневой ключ и и хочу, чтобы ключ в моем ответе был другим (например, предоставляя подмножество коллекции)? Вместо использования present я могу снова использовать represent. За исключением этого раза, вместо отключения корневого ключа путем передачи «false», я могу дать ему имя ключа:

get do
  my_stuff = Stuff.find_by(user_id: current_user)

  Entities::StuffEntity.represent(
    my_stuff,
    root: :my_stuff
  )
end
person Allison    schedule 03.09.2020