Сериализировать массив моделей с помощью active_model_serializers

Я пытаюсь отправить сериализованную версию модели в представление в качестве параметра, используя gem active_model_serializers

#app/serializers/admin_serializer.rb
class AdminSerializer < ActiveModel::Serializer
  attributes :id, :email, :access_locked?
end


#app/controllers/dashboard/admins_controller.rb
  def index
    @search = Admin.search(params[:q])
    @admins = @search.result(:distinct => true).page(params[:page]).per(10)

    @page_entries_info = view_context.page_entries_info @admins
    # render json: @admins
    respond_to do |format|
      format.html
      format.js
      format.json {render json: @admins}
    end
  end



#app/views/dashboard/admins/index.html.erb
  <%= debug (ActiveModel::Serializer::Adapter.adapter_class(:json_api).new(ActiveModel::Serializer.serializer_for(@admins.first).new(@admins.first),{}).to_json) %>
  <%= debug (@admins.all.map{|admin| AdminSerializer.new(admin).to_json}) %>

Приведенные выше отладки дают следующий ответ:

--- '{"data":{"id":"1","type":"admins","attributes":{"email":"[email protected]","access_locked?":false}}}' //returned by the first debug


---
- '{"object":{"id":36,"email":"[email protected]","created_at":"2016-03-28T05:15:17.546Z","updated_at":"2016-03-28T05:15:17.546Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":20,"email":"[email protected]","created_at":"2016-03-28T05:15:16.304Z","updated_at":"2016-03-28T05:15:16.304Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":22,"email":"[email protected]","created_at":"2016-03-28T05:15:16.459Z","updated_at":"2016-03-28T05:15:16.459Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":37,"email":"[email protected]","created_at":"2016-03-28T05:15:17.624Z","updated_at":"2016-03-28T05:15:17.624Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":5,"email":"[email protected]","created_at":"2016-03-28T05:15:15.139Z","updated_at":"2016-03-28T05:15:15.139Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":14,"email":"[email protected]","created_at":"2016-03-28T05:15:15.838Z","updated_at":"2016-03-28T05:15:15.838Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":27,"email":"[email protected]","created_at":"2016-03-28T05:15:16.848Z","updated_at":"2016-03-28T05:15:16.848Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":2,"email":"[email protected]","created_at":"2016-03-28T05:15:14.873Z","updated_at":"2016-03-28T05:15:14.873Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":10,"email":"[email protected]","created_at":"2016-03-28T05:15:15.527Z","updated_at":"2016-03-28T05:15:15.527Z"},"instance_options":{},"root":null,"scope":null}'
- '{"object":{"id":15,"email":"[email protected]","created_at":"2016-03-28T05:15:15.916Z","updated_at":"2016-03-28T05:15:15.916Z"},"instance_options":{},"root":null,"scope":null}'

В первой отладке я сериализую только один объект, а во второй пытаюсь сделать это для массива объектов. Первая отладка правильно возвращает сериализованную версию объекта (в формате json_api), а вторая отладка — нет. Пробовал и ArraySerializer, но безуспешно: ActiveModel::Serializer::ArraySerializer.new(@admins, each_serializer: AdminSerializer).as_json как мне добиться желаемой сериализации. Более того, если это будет достигнуто, могу ли я использовать какую-то другую упрощенную версию этого? Поскольку этот оператор отладки слишком многословен.

Пробовал все упомянутые здесь решения - Как вы инициализируете класс ActiveModel::Serializer массивом ActiveRecord::Relation?

Основная проблема, которую я пытаюсь решить, заключается в том, что в методе index административного контроллера объект Admin передается как PORO в файл index.html. Но мне нужна сериализованная версия json этого объекта, чтобы я мог передать ее своим компонентам реакции в качестве реквизита

index отображает правильный json при запуске http://dashboard.localhost.com:3000/admins.json введите здесь описание изображения

ОБНОВЛЕНИЕ №1 для метода индекса

def index
    @search = Admin.search(params[:q])
    @admins_array = @search.result(:distinct => true).to_a
    if params[:page]
      @admins = @search.result(:distinct => true).page(params[:page][:number]).per(10)
      @admins_json_array = Kaminari.paginate_array(@admins_array).page(params[:page][:number]).per(10)
    else
      @admins = @search.result(:distinct => true).page(1).per(10)
      @admins_json_array = Kaminari.paginate_array(@admins_array).page(1).per(10)
    end
    @admins_json = ActiveModel::SerializableResource.new(@admins_json_array.to_a)
    ...
    ...
    ...
end

person vipin8169    schedule 29.03.2016    source источник
comment
У вас есть репо, в котором я мог бы клонировать и попробовать это?   -  person NullVoxPopuli    schedule 29.03.2016
comment
Нет, я не могу этого сделать. Не достаточно привилегированный   -  person vipin8169    schedule 29.03.2016
comment
Можете ли вы создать небольшой репозиторий с достаточным количеством кода, чтобы воспроизвести проблему?   -  person NullVoxPopuli    schedule 29.03.2016


Ответы (4)


У меня есть контроллер, в котором мне нужно указать сериализатор из-за того, что мне нужны разные атрибуты из сериализатора по умолчанию.

В контроллере:

  def index
    search = User.ransack(search_params)
    render json: search.result, each_serializer: MembershipRenewalSerializer::MemberSerializer
  end

Итак, просто чтобы все заработало, что произойдет, если вы укажете опцию each_serializer?

Редактирует:

Внешний контроллер:

ActiveModel::SerializableResource.new(
  User.first(2), 
  each_serializer: MembershipRenewalSerializer::MemberSerializer
).to_json

Обратите внимание, что без указания each_serializer SerializableResource будет использовать UserSerializer.

Редактировать № 2,

Похоже, с данными @admins происходит что-то странное.

Попробуйте преобразовать в массив:

ActiveModel::SerializableResource.new(@admins.to_a).to_json 

Редактировать №3

Чтобы разбить массив на страницы, попробуйте следующее:

@search = Admin.search(params[:q])
@results = @search.result(:distinct => true).to_a
@admins = Kaminari.paginate_array(@results).page(params[:page]).per(10)
person NullVoxPopuli    schedule 29.03.2016
comment
index render json работает должным образом и отображает json в правильном формате, как указано в json_api. обновил мой вопрос, чтобы отразить это состояние - person vipin8169; 29.03.2016
comment
это сработало для меня в моей консоли рельсов: ActiveModel::SerializableResource.new(User.first(2)).to_json - person NullVoxPopuli; 29.03.2016
comment
<%= debug(ActiveModel::SerializableResource.new(@admins.first(2)).to_json) %> у меня тоже работает... но, к сожалению, <%= debug(ActiveModel::SerializableResource.new(@admins).to_json) %> нет. приводит к undefined method query_parameters для nil:NilClass` - person vipin8169; 29.03.2016
comment
Интересно, @admins это какой-то странный объект... что происходит, когда вы добавляете .to_a к администраторам, так что @admins.to_a. Кроме того, не могли бы вы дать вывод @admins.class.name? - person NullVoxPopuli; 29.03.2016
comment
(byebug) @admins.class.name ActiveRecord::Relation - person vipin8169; 29.03.2016
comment
ну тогда это может быть баг. Решил ли to_a вашу проблему на данный момент? - person NullVoxPopuli; 29.03.2016
comment
(byebug) @admins.to_a [#‹Идентификатор администратора: 36, электронная почта: [email protected], зашифрованный_пароль: $2a$10$u1E0eoEymfPs.rmUu9K.... - person vipin8169; 29.03.2016
comment
правильно, но получилось ли ActiveModel::SerializableResource.new(@admins.to_a).to_json? - person NullVoxPopuli; 29.03.2016
comment
о да, это сработало как шарм. <%= debug(ActiveModel::SerializableResource.new(@admins.to_a).to_json) %> - person vipin8169; 29.03.2016
comment
В чем основная проблема? Мне пропинговать вас в slack? - person vipin8169; 29.03.2016
comment
может быть проще, да. Я все еще пытаюсь понять, как воспроизвести это на моей машине. - person NullVoxPopuli; 29.03.2016
comment
Можете ли вы опубликовать это как ответ, чтобы я мог принять это - person vipin8169; 29.03.2016
comment
Добавлен. Я также пинговал вас в Slack на канале #needhelp для продолжения. - person NullVoxPopuli; 29.03.2016
comment
Как теперь добавить ссылки на страницы? - person vipin8169; 29.03.2016
comment
может быть, на вашем массиве вызовите @paginated_array = Kaminari.paginate_array(@your_array).page(3).per(1)? - person NullVoxPopuli; 29.03.2016
comment
@vipin8169 Я добавил в свой пост правку №3 с советом по разбивке на страницы. - person NullVoxPopuli; 29.03.2016
comment
обновил метод индекса в соответствии с вашим предложением, но все еще не смог получить данные разбиения на страницы - person vipin8169; 29.03.2016
comment
Есть ли способ сделать небольшое репо, воспроизводящее это? Это здорово помогло бы команде ams :-) - person NullVoxPopuli; 29.03.2016
comment
опубликовал новый sol - stackoverflow.com/questions/36301450/ - person vipin8169; 30.03.2016
comment
ActiveModel::SerializableResource устарел в пользу ActiveModelSerializers::SerializableResource - person Touré Holder; 17.02.2019

Следуйте инструкциям: Сериализация до рендеринга контроллера

Вы можете использовать ActiveModel::SerializableResource.new(@admins, adapter: :json_api).to_json

in index.html.erb

<%= debug (ActiveModel::SerializableResource.new(@posts, adapter: :json_api).to_json) %>

ниже вывод (с использованием сообщений)

'{"data":[{"id":"1","type":"posts","attributes":{"title":"first post","body":null}},{"id":"2","type":"posts","attributes":{"title":"second post","body":null}}],"links":{}}
person abookyun    schedule 29.03.2016
comment
Это не сработало. все еще не получили данные в указанном формате - person vipin8169; 29.03.2016
comment
PS: я делаю это в файлах просмотра. - person vipin8169; 29.03.2016
comment
Я забыл '.to_json'. Попробуй это. - person abookyun; 29.03.2016
comment
без to_json, по крайней мере, я получаю некоторые данные. Я получаю следующее исключение, как только добавляю to_json =› undefined method query_parameters for nil:NilClass github.com/rails- API/active_model_serializers/issues/1268 - person vipin8169; 29.03.2016
comment
Как отредактированный ответ, я уверен, что он работал с @posts, который представляет собой массив экземпляров Post. Не могли бы вы распечатать содержимое вашего @admins для дальнейшей отладки? - person abookyun; 29.03.2016
comment
Да, я разместил здесь весь вывод, см. последний комментарий — github.com/rails -api/active_model_serializers/issues/1268 - person vipin8169; 29.03.2016
comment
ActiveModel::SerializableResourcenew(model) работал у меня. Спасибо. - person rom5jp; 27.07.2018

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

def api_response(data)
  render json: wrap_answer(data)
end

def wrap_answer(data)
  if data.respond_to?(:each)
    ActiveModel::Serializer::CollectionSerializer.new(data, each_serializer: ActiveModel::Serializer.serializer_for(data.first))
  else
    data
  end
end
person ZZ4    schedule 24.02.2020

должен был преобразовать это в строку и использовать json.stringify, чтобы сделать это строкой и упростить вашу жизнь

person Kumar Vadivel    schedule 02.08.2020
comment
См. раздел Как ответить о том, как опубликовать полный ответ, а не предложение. - person camille; 02.08.2020