6
votes

When I am trying to load data from rails db with emberjs + ember data I am getting this error

Uncaught TypeError: Cannot call method 'map' of undefined

Here's the coffescript code:

window.Cosmetics = Ember.Application.create

Cosmetics.store = DS.Store.create
  revision: 4
  adapter: DS.RESTAdapter.create 
    bulkCommit: false

Cosmetics.admin_user = DS.Model.extend({
  name: DS.attr('string')
  email: DS.attr('string')
});

Cosmetics.view = Ember.View.extend
  templateName: 'ember/views/aaa'

Cosmetics.admin_user.reopenClass
  url: 'admin/user'

Cosmetics.store.findAll(Cosmetics.admin_user)

Controller gets proper JSON data. I've tried mapping the code from the examples found over the internet but nothing helped. Any ideas? I guess I'm doing sth wrong. Thanks in advance for any help.

5
Could you post an example of the object being returned from the server? There was also a bug with older versions of ember and the newer versions of data that would trigger the above error, what version of ember are you using?Cory Loken
@CoryLoken Here's the sample object returned by rails - object returned. About the emberjs version, I am using the one shipped with ember-rails gem, yet to be on a safe side I've tried using the latest downloaded from github (0.9.7.1) but without success.thyforhtian
Have the same problem with the emberjs version packaged with ember-rails 0.6.0Akshay Rawat
Post the code in your serializer maybe?mehulkar

5 Answers

4
votes

I had the exactly same problem. What solved it for me was adding the root node when rendering the JSON in the index action in my controller. That meant changing this line:

format.json { render json: @things }

to this:

format.json { render json: { things: @things }}

That's because Ember-data requires the root node in the JSON object, but Rails doesn't include it by default.

I hope that helps.

4
votes

Found the problem, not sure about the solution.

If your resource is being served under a namespace, eg

App.Event = DS.Model.extend({
  name: DS.attr('string'),
});

App.Event.reopenClass({
  url: 'api/event'
})

When ember-data parses the json response, it does something like json[plural] in findAll which should be json['events'], however the plural is calculated to be json['api/events'], and hence the error. I'll ask around and probably raise a ticket for this.

Update

I've created a ticket for this here

Workaround

As a hack, I'm doing this:

def index
  respond_to do |format|
    format.json { render json: { 'api/events': Event.all } }
  end
end
3
votes

ember-data expects findAll results to be nested under the pluralized form of the model:

What ember-data is expecting:

{
    "users": [
        {
            "activated": null, 
            "created_at": "2012-05-14T19:35:44Z", 
            "email": "[email protected]", 
            "id": 1, 
            "name": "john doe", 
            "updated_at": "2012-05-15T20:23:06Z"
        }
    ]
}

What it is getting in your example:

[
    {
        "activated": null, 
        "created_at": "2012-05-14T19:35:44Z", 
        "email": "[email protected]", 
        "id": 1, 
        "name": "john doe", 
        "updated_at": "2012-05-15T20:23:06Z"
    }
]

Specifically, the error comes from ember taking the JSON response and running "map" over everything under the "users" key, which in your case does not exist, hence "map" is being called on "undefined".

0
votes

I've finally found the solution!

I'm not sure if this should be done this way but it was enough to get rid of bulk commits. So what the store should look like is:

Cosmetics.store = DS.Store.create
  revision: 4
  adapter: DS.RESTAdapter.create 

bulkCommit: false was causing the Uncaught TypeError: Cannot call method 'map' of undefined error.

This problem seems to be related only to ember-data when used in rails apps.

I seem to have rushed a little bit as what seemed to solve the problem, caused anothers ;|

0
votes

The root cause of the problem is pluralize function in rest_adapter.js therefore the solution is to fix it ;)

  DS.RESTAdapter.reopenClass({
    pluralize: function(name) {
      if (!this.plurals[name])
        name = name.substring(name.lastIndexOf('/')+1);

      return this.plurals[name] || name + "s";
    }
  });