Reputation: 1765
Let me explain shortly what I mean. I'm writing an app that makes use of Ember and Rails. Every employee can give other co-workers a kudo. He can't know how many others received. I can only know how many left kudos I have to give and how many I received from others.
But I can't really understand how to communicate with Rails. As a picture is worth a thousand words, please take a look at this: kudos app http://wstaw.org/m/2013/03/25/kudos.png
When the app starts I load a list of users pointing to /users. Current user is at /currentuser. Current user differs in that it has additional fields like kudosReceived and kudosLeft.
Let's suppose I'd like to add Joe a kudo. I click on a button, and then, what? Suppose that when I go to /kudos/userid rails will do its magic. It just adds Joe a kudo. But I'd also like to get the updated current user data (remember, it is at /currentuser).
What should I send? Should I first use CREATE or UPDATE method on the controller? How can I obtain current user new data? In a callback? Or should I use /currentuser with GET. But when?
This is what I have now, but I'm completely unsure how correct it is
// application.handlebars
<h1>My Kudos</h1>
<div id="kudos-content">
<ul id="kudos-list">
{{#with controllers.current}}
<li>
<p>{{firstName}} {{lastName}}</p>
<p><img {{bindAttr src="imageUrl"}} /></p>
<p>received: {{kudosReceived}}</p>
<p>left: {{kudosLeft}}</p>
</li>
{{/with}}
{{#each user in controllers.users}}
<li>
<p>{{user.firstName}} {{user.lastName}}</p>
<img {{bindAttr src="user.imageUrl"}} />
<a href="#" {{action "addKudo" user.id target="controller.controllers.kudo"}}>(+)</a>
</li>
{{/each}}
</ul>
</div>
Sks.KudoController = Ember.ObjectController.extend({
addKudo: function(userId) {
// create a new record on a local transaction
this.transaction = this.get('store').transaction();
// don't really know what next
}
});
The next problem is how to use /kudo/userid in {{action}}
Upvotes: 1
Views: 268
Reputation: 10562
It sounds like it isn't necessary to care about the Kudo
in the client as anything but a counter. The client doesn't know where any particular Kudo
came from or anything else about it. In that case, it should be sufficient to treat Kudo
as nothing more than a -1
on the number of Kudo
s the current user has left.
If this is the case, then creating a DS.Model
class for Kudo
, worrying about relationships, storing everything about a Kudo
in the store, and posting JSON to the server is 100% overkill. This is ESPECIALLY true if the server doesn't expect JSON for a Kudo
and simply creates a Kudo
server-side for a target user, or increments a counter, or whatever.
If simply hitting that URL is all that is necessary, and it sounds like it is, then I'd suggest simply using jQuery.ajax() to tap the URL. I'd also assume that a successful response means that the current user has one less kudosLeft
, and I'd simply handle that in the success callback, rather than worrying about syncing the currentUser model to the server. If that isn't ideal, you can call reload
on the currentUser to fetch the new data manually, assuming the server has been keeping track of kudosLeft
on the server-side model.
First, add needs: ['current']
to your KudoController so you have access to the currentUser.
Then in addKudo
addKudo: function(user) {
jQuery.post('/kudo/' + user.get('id'), jQuery.proxy(function () {
this.decrementProperty('controllers.current.kudosLeft');
}, this));
}
This assumes that CurrentController
is an ObjectController
so that it passes the set through to its content
.
Finally, update your {{action}}
to include the full User
object instead of just the id:
<a href="#" {{action "addKudo" user target="controller.controllers.kudo"}}>(+)</a>
A few notes:
(1) It is possible using this scheme for the client to become out of sync with the server, if for instance, the user has another copy of the app open and sends Kudo
s there. This may or may not be a problem. In Stack Overflow, for instance, the UI dynamically updates when votes or accepted answer status changes. It might be accepted in your case to simply not care about keeping every little thing synced if it isn't of significance. What you might do in this case is have your /kudos
endpoint return a particular status code if the client attempts to send a kudo when the user has none left. The callback on the ajax call could test for that status and trigger a reload on the user, or just reset the kudosLeft
property to 0.
(2) Setting the kudosLeft
property like this will mark the record as dirty and thus will cause an update when the store is committed. What you can do is have a computed property, such as displayKudosLeft
that is initially set to the kudosLeft
attribute, but can be changed by the app to update the display without marking the record as dirty.
As for when to use ember-data, and when to use $.ajax, well, that depends. How large is your API and how RESTful is it? Do you use active_model_serializers
, which play nicely with ember-data? Do you have a lot of relationships that need to be reflected on the client? Are you doing a lot of "one-off" updating of attributes, or hitting API end points that don't actually expect to receive JSON in order to have their effect?
There are huge apps (or, at least one) that don't use ember-data and do just fine. Discourse, for instance, uses a thin wrapper around $.ajax
, and it does just fine.
Upvotes: 1