Неопубликованная загрузка объектов с нестандартными именами классов в EmberJS с помощью Rails+active_model_serializers

У меня есть несколько моделей в Rails, которые выглядят примерно так:

class Issue < ActiveRecord::Base
  belongs_to :reporter, class_name: 'User'
  belongs_to :assignee, class_name: 'User'
  has_many :comments
end

class User < ActiveRecord::Base
end

class Comment < ActiveRecord::Base
end

с такими сериализаторами:

class IssueSerializer < ActiveModel::Serializer
  attributes :id
  embed :ids, include: true

  has_one :reporter, :embed => :ids
  has_one :assignee, :embed => :ids
end

class UserSerializer < ActiveModel::Serializer
  attributes :id, :name
end

class CommentSerializer < ActiveModel::Serializer
  attributes :id, :body
end

Это создает JSON, который выглядит примерно так:

{
  "issues": [
    {
      "id": 6,
      "reporter_id": 1,
      "assignee_id": 2,
      "comment_ids": [
        3
      ]
    },
  ],
  "comments": [
    {
      "id": 3
      "body": "Great comment"
    }
  ],
  "reporters": [
    {
      "id": 1
      "name": "Ben Burton"
    }
  ],
  "assignees": [
    {
      "id": 2
      "name": "Jono Mallanyk"
    }
  ]
}

Проблема в том, что загруженные неопубликованные объекты JSON репортеров и уполномоченных не распознаются Ember как объекты пользователя, и я вижу следующую ошибку:

Uncaught Error: assertion failed: Your server returned a hash with the key reporters but you have no mapping for it

я не хочу удалять

embed :ids, include: true

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

Есть несколько потенциальных способов решить эту проблему, которые я рассматривал:

  • Если бы метод встраивания для ActiveModel::Serializer принимал список моделей в своем параметре include, это могло бы фильтровать ответ JSON, чтобы включать только загруженные неопубликованные комментарии.
  • Модель данных Ember может быть настроена на боковую загрузку пользователей из «пользователей», «репортеров» и «правопреемников»… но, насколько я могу судить из источника, она поддерживает только один ключ для sideloadAs.
  • Каким-то образом игнорировать/отключать ошибки боковой загрузки для неизвестных ключей (вероятно, наименее разумный подход).

Есть ли еще один вариант, который мне здесь не хватает? Я думаю, мне, возможно, придется написать исправление и отправить запрос на включение либо в rails-api/active_model_serializers, либо в emberjs/data, либо в оба.

EDIT: мой временный обходной путь для этого — изменить IssueSerializer, чтобы сериализовать только идентификаторы для репортера и правопреемника:

class IssueSerializer < ActiveModel::Serializer
  attributes :id, :reporter_id, :assignee_id
  embed :ids, include: true

  has_many :comments, :embed => :ids
end

person benburton    schedule 12.03.2013    source источник
comment
Не могли бы вы показать свою модель проблемы?   -  person Willem de Wit    schedule 12.03.2013
comment
Ваш ответ ниже был правильным.   -  person benburton    schedule 12.03.2013
comment
Какую версию Ember-данных вы используете?   -  person Willem de Wit    schedule 13.03.2013


Ответы (3)


У меня была аналогичная проблема, и я нашел решение в ActiveModel::Serializers readme. Вы можете использовать опцию :root. Попробуйте что-то вроде этого для сериализатора задач:

class IssueSerializer < ActiveModel::Serializer
  attributes :id
  embed :ids, include: true

  has_one :reporter, :root => "users"
  has_one :assignee, :root => "users"
  has_many :comments
end
person lroza    schedule 02.04.2013
comment
Это стирает ранее загруженные объекты, поэтому, если есть некоторые пользовательские репортеры, которые не являются правопреемниками, это не сработает. Все равно полезно знать. - person rogermushroom; 26.10.2013

Вы должны прочитать эту страницу. Раздел Revision 12 объясняет загрузку данных одного и того же типа:

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

Ваша модель должна быть такой:

App.Issue  = DS.Model.extend({
  reporter: DS.belongsTo('App.User'),
  assignee: DS.belongsTo('App.User'),
  comments: DS.hasMany('App.Comment')
});

Результат JSON должен иметь ключ для пользователей:

{
  "issues": [
    {
      "id": 6,
      "reporter_id": 1,
      "assignee_id": 2,
      "comment_ids": [
        3
      ]
    },
  ],
  "comments": [
    {
      "id": 3
      "body": "Great comment"
    }
  ],
  "users": [
    {
      "id": 1
      "name": "Ben Burton"
    },{
      "id": 2
      "name": "Jono Mallanyk"
    }
  ]
}

Поскольку вы настроили в своей модели, что reporter имеет тип User, Ember ищет пользователя в результате.

person Willem de Wit    schedule 12.03.2013
comment
Соглашение, согласно которому Ember ожидает пользователей как набор пользовательских моделей с боковой загрузкой, несовместимо с соглашением active_model_serializers, согласно которому объекты встраиваются на верхнем уровне с именем поля. Было бы здорово, если бы он загружал объекты User под пользователями, но это не так. - person benburton; 12.03.2013
comment
Соглашение для active_model_serializers все еще находится в дорожной карте. У вас все еще есть проблема с другим исключением? - person Willem de Wit; 12.03.2013
comment
Решение, которое у меня есть на данный момент, состоит в том, чтобы просто вообще не загружать пользователей, просто сериализуя идентификаторы в задаче (см. мое редактирование выше). Очевидно, это не очень хорошо, потому что требуется второй запрос, если модели пользователя отсутствуют в магазине. Немного подумав об этом, я пришел к выводу, что действия Эмбер вполне разумны. Я думаю, что у active_model_serializers есть (может быть?) ошибка в том, что она сериализует модели на основе псевдонима, а не имени класса. - person benburton; 12.03.2013

У меня была такая же проблема, добавление include: false в ассоциацию помогло мне.

    embed :ids, include: true
    attributes :id, :title

    has_many :domains, key: :domains, include: false
    has_many :sessions, key: :sessions
person tomeara    schedule 08.05.2014