简体   繁体   中英

Inform ember-data about server changes

I am currently planning a complex application using ruby on rails and ember.js. What I have seen about ember-data so far is that it caches records automatically; post.comments will first result in a Ajax-call to fetch all comments for the given post, but if the user visits the same route the next time, it will just fetch the records from the store-cache.

The problem is: What if another user added a comment to this post? How to tell ember it has to reload its cache because something changed?

I already thought about a solution using websockets to tell clients which stuff to reload - but I don't think this is best-practice. And in addition, I can't imagine this isn't a common problem, so I am wondering what other developers are doing to solve this issue.

I tried to implement model updating in (experimental) chat application. I have used SSE : ActionController::Live on server side (Ruby on Rails) and EventSource on client side.

Simplified code:

App.MessagesRoute = Ember.Route.extend({
  activate: function() {
    if (! this.eventSource) {
      this.eventSource = new EventSource('/messages/events');

      var self = this;
      this.eventSource.addEventListener('message', function(e) {
        var data = $.parseJSON(e.data);
        if (data.id != self.controllerFor('messages').get('savedId')) {
          self.store.createRecord('message', data);
        }
      });
    }
  }
});

App.MessagesController = Ember.ArrayController.extend({
  actions: {
    create: function() {
      var data = this.getProperties('body');
      var message = this.store.createRecord('message', data);
      var self = this;
      message.save().then(function (response) {
        self.set('savedId', response.id);
      });
    }
  }
});

The logic is simple: I'm getting each new record from EventSource. Then, if record was created by another client, the application detects it and new record being added to store using ember-data 's createRecord . Suppose this logic may have some caveats, but at least it serves well as 'proof of concept'. Chat is working.

Full sources available here: https://github.com/denispeplin/ember-chat/

I have something to say about reloading: you probably don't want to perform full reloading, it's resource-consuming operation. Still, your client side needs some way to know about new records. So, getting new records one-by-one via SSE is probably the best option.

If you just want to get rid of caching you can force a reload every time user navigates to comments route . But this largely depends on what you are trying to acheieve, I hope comments is just an example.

If you want your ui to get updated automagically with changes in server, you need some communication with server, some polling mechanism like websocket or polling from a webworker . Then you may reload the list of changed records sent from server. You are probably on the right track with this.

You can as well take a look at the orbitjs standalone library that integrates well with Ember. This is more useful if you require local storage as well and got to manage the multiple data sources.

This is really a common problem with any web application, no matter what framework you are using. From my point of view, there are two main options. One: You have a service that polls the server to check to see if there are any changes that would require you to reload some of your models, have that service return those model IDs and refresh them. The other option is as you suggested, using a websocket and pushing notifications of model changes/new models themselves.

I would opt to actually just send the comment model itself, and push it into the Ember store and the associated post object. This would reduce the need to hit the server with a hard refresh of your model. I am currently using this method with my Ember app, where there is an object that contains overview data based on all the models in my app, and when a change is made in the backend, my websocket server pushes the new overview data to me application.

UPDATE:: I meant for this to be a comment, not an answer, oh well.

I've had this same issue with mobile app development. While websockets seemed like the first answer, I was worried about scalability issues with limited server resources. I decided to stick with the Ajax call to fetch newly modified records. This way server resources are only used if the user is active. However, as others pointed out, returning all comments every single time you need data makes your cacheing useless and is slow. I suggest updating your rails server to accept an optional timestamp. If the timestamp is not supplied, then every comment is retrieved. If a timestamp is supplied, then only return comments where the updated_at column is >= the supplied timestamp. This way, if no comments were added or modified since your last call, then you quickly get back an empty list and can move on. If results are returned, you can then merge them with your existing list and show the updated comments.

Example of fetching newly created or modified comments

if params.has_key?(:updated_since)
  comments = Post.find(params[:id]).comments.where("updated_at >= ?", params[:updated_since])
else
  comments = Post.find(params[:id]).comments
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM