Виноградная сущность для хэша со строковыми ключами не работает

Я использую 'grape-entity', '~> 0.7.1'

У меня есть хеш в формате:

temp_data = [{sheet_index: 0, other_names: []},{'sheet_index' => 1, 'other_names': ['a']}]

И у меня есть следующие объекты

 class Sheet < Grape::Entity
   expose :sheet_index, documentation: {type: Integer, desc: "Sheet index"}
   expose :other_names, documentation: {type: Array, desc: "Other names"}
 end

 class Sheets < Grape::Entity
  present_collection true

  expose :items, as: 'sheet_history', using Entities::Sheet
 end


# response from the entities
present temp_data, with: Entities::Sheets

Теперь мне нужно убедиться, что независимо от типа ключей в моем хэше он все равно должен давать мне правильный вывод для приведенного выше случая.

expected_response = {"sheet_history" => [{"sheet_index"=>0, "other_names"=>[]}, {"sheet_index"=>1, "other_names"=>["a"]}]}

но ответ, который я получаю, находится в формате ниже

actual_response = {"sheet_history" => [{"sheet_index"=>0, "other_names"=>[]}, {"sheet_index"=>nil, "other_names"=>nil}]}

поэтому в фактическом ответе sheet_index и other_names второго элемента равны нулю, потому что их ключи были строками, а не символами. (См. temp_data.)

Я сослался на https://github.com/ruby-grape/grape-entity/pull/85, чтобы получить приведенную выше реализацию, но я все еще не могу заставить ее работать без использования HashWithIn DifferentAccess или OpenStructs.


person VXCSL    schedule 02.03.2020    source источник
comment
Вопросы, требующие помощи в отладке (почему этот код не работает?), должны включать желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для их воспроизведения, в самом вопросе. См.: Как создать минимальный воспроизводимый пример. Ссылки на код GitHub недостаточно; Нам нужно увидеть, что вы пробовали.   -  person the Tin Man    schedule 02.03.2020
comment
@theTinMan Я добавил необходимые изменения (ожидаемый и фактический ответы, которые я могу воспроизвести, и причину расхождения в двух ответах). Пожалуйста, проверьте сейчас.   -  person VXCSL    schedule 03.03.2020
comment
См. раздел Что такое проблема XY?. Слишком часто мы спрашиваем, как исправить Y, когда мы должны спросить, как сделать X. Как вы собираете свои данные, которые приводят к хэшу с ключами String и Symbol? Сделайте резервную копию и посмотрите на это и посмотрите, сможете ли вы привести ключи к согласованным типам, либо к строкам, либо к символам.   -  person the Tin Man    schedule 05.03.2020


Ответы (1)


Вам не хватает двоеточия после using, но я бы не стал настраивать несколько таких сущностей, так как это может привести к нестабильному поведению. Попробуй это:

# Dummy definition of your class
class Item
  include ActiveModel::Serialization

  attr_accessor :sheet_index
  attr_accessor :other_names

  def initialize(index, names)
    @sheet_index = index
    @other_names = names
  end
end
items = []
items << Item.new(0, [])
items << Item.new(1, ['a'])
=> [
  #<Item:0x00007f860f740e40 @other_names=[], @sheet_index=0>, 
  #<Item:0x00007f860f513618 @other_names=["a"], @sheet_index=1>
]
# Entity Definition
class Sheet < Grape::Entity
  # The first arg here is the key to use for a collection, 
  # the second is the key to use for a single object
  root 'sheet_history', 'sheet_history'

  expose :sheet_index, documentation: {
    type: Integer, 
    desc: "Sheet index" # Plz use locales
  }

  expose :other_names, documentation: {
    type: Array, 
    desc: "Other names" # Plz use locales
  }
end
# Test it
representation = Sheet.represent(items)
=> {
  "sheet_history"=>[
    #<Sheet:70106854276160 sheet_index=0 other_names=[]>, 
    #<Sheet:70106854275680 sheet_index=1 other_names=["a"]>
  ]
}
# This is just more a more readable, but as you can see it's 
# both mapping all the attributes correctly and 
# setting the root key that you wanted:
representation['sheet_history'].map do |r| r.serializable_hash end
=> [
  {
    :sheet_index=>0, 
    :other_names=>[]
  }, 
  {
    :sheet_index=>1, 
    :other_names=>["a"]
  }
]

# Endpoint
get do
  items = current_user.items # or whatever
  present items, with: Entities::Sheet
end

Вы можете отправить свой массив хэшей методу represent, но ему не нравится строковый ключ. В идеале вы должны передавать объекты БД своей сущности вместо хэшей, но, если вы по какой-то причине не можете, я бы передал temp_data.map(&:symbolize_keys) в качестве вашего аргумента сущности, чтобы гарантировать, что ключи верхнего уровня в хэше, который он анализирует, являются символами.

person Allison    schedule 04.09.2020