Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Side-loading objects with non-standard class names in EmberJS with Rails+active_model_serializers

I have a few models in Rails that look something like this:

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

with serializers like so:

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

This produces JSON that looks something like the following:

{
  "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"
    }
  ]
}

The problem is that the side-loaded reporters and assignees JSON objects aren't recognized by Ember as User objects, and I see the following error:

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

I don't want to remove

embed :ids, include: true

from my IssueSerializer, because then the comments wouldn't be serialized.

There are a few potential ways to solve this that I've considered:

  • If the embed method for ActiveModel::Serializer accepted a list of models in its include option, this could filter the JSON response to only include side-loaded comments.
  • Ember data's model could be configured to side load users from "users", "reporters" and "assignees"... but as far as I can tell from the source it only appears to support one key for sideloadAs.
  • Somehow ignore/disable side-loading errors for unknown keys (probably the least sane approach).

Is there another option I'm missing here? I think I may have to write a fix and submit a pull request to either rails-api/active_model_serializers, emberjs/data, or both.

EDIT: My temporary workaround for this is to change the IssueSerializer to only serialize the ids for reporter and assignee:

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

  has_many :comments, :embed => :ids
end
like image 469
benburton Avatar asked Mar 12 '13 14:03

benburton


2 Answers

I had similar problem and have found solution at ActiveModel::Serializers readme. You can use :root option. Try something like this for issue serializer:

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

  has_one :reporter, :root => "users"
  has_one :assignee, :root => "users"
  has_many :comments
end
like image 137
lroza Avatar answered Oct 16 '22 10:10

lroza


You should read this page. The section of Revision 12 explains about the sideloading of data of the same type:

Now, homeAddress and workAddress will be expected to be sideloaded together as addresses because they are the same type. Furthermore, the default root naming conventions (underscore and lowercase) will now also be applied to sideloaded root names.

Your Model should be like:

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

The JSON Result should have a key for the users:

{
  "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"
    }
  ]
}

Because you configured in your Model that the reporter is of type User, Ember search for a user in the result.

like image 36
Willem de Wit Avatar answered Oct 16 '22 09:10

Willem de Wit