I have a well behaving API that I'm going against but in one case there is a twist that I'm hoping Ember can accommodate. Specifically when I call DELETE on an endpoint, the default behaviour is to not truly delete it but rather to set the workflow status to "marked_for_deletion" which makes it invisible to most apps. There are, however, situations where I want to ACTUALLY delete the record and doing this is simply a matter of including a URL parameter of immediate=true. If I were doing this with AJAX it would be as simple as can be but I'm wondering what the "right" way of doing this is with Ember-Data.
Anyone have a view?
must use query parameter. It's not related with ember-data check this guide.
Be careful because API will be changed
Related
This topic har been discussed on stackoverflow before, but not with latest version of ember data, I think. At least none of the suggestions I have found have worked for me.
I use the latest version of Ember and Ember data (versjon 2.13.0). I use the JsonApiAdapter.
Scenario
After I load a record from the server I want to do a few changes to some of its properties. These changes shall not make the record dirty, and the changed attributes shall not show up in the record.changedAttributes(). Any changes the user may do after that shall make the record dirty.
Searching for a solution
I have tried to manually change the isDirty flag, but it didn't do it. I have also tried to find the place in the ember data code that sets the state after a record has been loaded (because essentially I am trying to do the same thing) but I haven't found where it is.
I have also tried record.send('pushedData'), but I didn't change anything of the state of the record.
Any help appreciated.
I know 3 methods which allow to modify server's response without dirtying records:
You can override adapter's handleResponse method and make modifications right in payload.
You can override serializer's normalize method.
You can load records from server with Ember.$.ajax method, modify response and then pass it to store's pushPayload method.
First two methods are good if you need to modify record after every load from server (no matter from what route/controller you do it). Both adapter and serializer can be model-specific. If you need to do it in only one place (controller or route), or if you need an access to route's/controller's variables - 3rd method is good.
I'm not aware about any way to mark record as dirty/not dirty. If you modify a record after it was stored, it becomes dirty.
While going from one route to another, I want to pass some data (especcially arrays). How is it possible?
Why can't we use query-params with arrays?
Is it a problem storing data in a specific service during transition?
Note:
I know there are some old questions those are nearly the same with this question. But their selected answers are no more applicable for Ember 2.x. Those questions are: 1, 2.
I´m not sure if queryparams won´t work with arrays as I only used it with single ids, but it would not be a good solutions even if it worked, there´s a limit on how much you can send by parameters and you should not bother any user with your data.
Just create a model to save your data for local use, so you can simply use the ember store
Use a service you´ll have to inject in every controller you want to use your data
I would prefer the model/store variant so you´ll be able to observe and just follow the normal flow which is also good if someone else has to maintain your code.
UPDATED
After testing with "transition.data"; not updating the history seems as a problem for us. So we again use "queryParams". The constraint is: do not pass a complex object between routes
OLD ANSWER
I'm using transition object for this purpose in an action while routing as the following:
let transition = router.transitionTo(route, model);
transition.data[propName] = propValue;
Also I wrote a component to use this code as link-to.
I am having trouble with a specific case using Ember-Data.
Typically Ember expects a model class, the route, the ajax request, and the returned JSON, to all follow a similar pattern.
The RESTAdapter tries to automatically build a URL to send to the server, which is ok for some situations, but I need full control over some of my request URLs particularly when it comes to appending additional parameters, or matching an API to a route that has a completely different URL structure.
Ember sadly, has no guides for this, though I did find something about the buildURL method
I am not comfortable enough rooting through the source code to find out what happens under the hood though I do not want to break ember data just to fix a few use cases.
I have set my RESTAdapter's namespace to api/rest
The model and resource I want to populate is view-debtors
The specific service I want to reach is at debtor/list
I also need to pass extra parameters for pagination ?page_size=10&page_number=1, for example.
I am completely lost how to do this. I cannot change the API structure... there are too many services depending on them.
Some Small Progress
I went ahead and used my current knowledge to get a little closer to the solution.
I created a model and called it "list"
I extended RESTAdapter for "list" to change the namespace to "api/rest/debtor"
I changed the model hook for "view-debtors" route to store.find('list')
The result now is that the AJAX call is almost correct... I just need to add those extra parameters to the server queries.
This is where I stand now... can I add those server queries via the model hook? or better yet can I also control server queries via ember actions to get new AJAX requests?
Stepping back a bit. Is my method so far a good practice? Because I am using a route's model hook, to set the model to list, will this only work if the routes URL is typed in directly?
So many questions :p
You can find by query which will append a query string onto the end of your request using the object provided.
// this would produce /api/rest/debtor/lists?page_size=1&page_number=10
this.store.find('list', {page_size:1, page_number:10});
Personally I think it's a bit hacky to go fudging the model names and namespace to make it supposedly fit your backend's url structure. It really depends on what you're attempting to do. If you want all the full features of CRUD using Ember-Data for this particular list of data, you're going to be hacking the end-point left and right. Whether or not Ember Data really helps you is questionable. If you are just reading data, I'd totally just fetch the data using jquery and sideload it into Ember Data.
var store = this.store;
$.getJSON('/api/rest/debtor/lists?page_size=1&page_number=10').then(function(json){
//fix payload up if necessary http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload
store.pushPayload('type', json);
}).then(function(){
return store.all('type'); // or store.filter('type') if you want to filter what is returned to the model hook
});
pushPayload docs
I have a question regarding some action accessing, i'm not talking here about authorization etc, but more about the direct access to actions.
Basically i have 2 question, 1 general and 1 more contextual:
Situation imaging i have an action : MyArticles/DeleteArticle/id
1) How can i prevent that if someone will just put this url with a proper id remove article? How can i say that it can only be used with a button on my website? And should this action be a get or post?
At this moment i use $.ajax and GET method ....
2) Now imagine i have many people, and if all th ppl are registered, they can delete each others article, what if i want to avoid that and let users only delete their own articles, because at this moment for example if they can guess the id they can directly access the action with id and delete it.
Can anyone provide explanation and some tips about that?
i'm not talking here about authorization etc
Yes, you are. The authorization to delete the article should take place within the action itself, it's not the responsibility of the calling code or of any UI which displays a link to the action.
How can i say that it can only be used with a button on my website?
I imagine any approach to that is going to complicate the issue tremendously. Understand how HTTP requests work... Your application isn't making the request to the action, the user is. They're doing so (in the general case) by clicking a link on an interface provided by your application, but the request itself is coming from the user. (Well, from the user's web browser, which is in their control and not yours.)
The most straightforward approach to this is to encapsulate authorization in the action itself (or, better still, in the model functionality being invoked by the action... but logically that's still part of the "request" being performed).
When you expose a piece of functionality which not everybody should be able to invoke, put the authorization on the functionality itself instead of on the UI which invokes it. That way no matter how it's invoked it always maintains the authorization, instead of just assuming that some other component maintained it.
You have a lot of control in MVC with respect to the USER. To allow a user to delete only his own work, you must remember in the database who wrote what. If this is the case - and you know it, a simple if statement in the beginning of the action will do the trick.
How do you paginate the request for related data? For example, if my Person has a thousand Task models attached to it if I do the following, in RESTful thinking, I would get all of them.
var tasks = person.get('tasks');
That would be way too much data. How do I force some query parameter onto the request that works behind the scenes? Ideally to an endpoint with something like this attached to the end of it.
?&offset=3&limit=3
Here is a fiddle to illustrate what I'm trying to accomplish in the IndexController. I have no idea what the "ember way" is to do paginated requests using ember-data.
It didn't exist when this question was first asked, but there is now an addon called ember-data-has-many-query that seems capable of this, at least for RESTAdapter and JSONAPIAdapter. It appears to have some quirks due to ember-data not yet supporting pagination as a first-class concept. If this makes you uneasy, there is always store.query, but this does require your API to support (in your example) a person_id filter parameter on the /tasks endpoint.
Related:
ember-data issue #3700: Support query params when fetching hasMany relationship
json-api issue #509: Pagination of to-many relationships is underspecified
(it doesn't look like this question involved JSON API, but the discussion is relevant)
As today there is still no default way to handle pagination in ember.
First we should probably look at the more simple thing, pagination of a findAll request.
This can be done with something like .query({page:3}), but leads to some Problems:
This is a good solution for classic pagination, but for a infinite-scroll you still need to manually merge the results.
The results are not cached, so moving forward and backward on an paginated list results in a lot of querys. Sometimes this is necessary if the list is editable, but often its not.
For the second problem I build a little addon called ember-query-cache that hooks into the store and allows you to cache the query results. A very short demo is available here.
Now if we talk about a relationship I would honestly recommend to use top level .query until you have better support from ember-data itself:
store.query('task', { person: get(person, 'id'), page: 3 }
There is nothing bad about it. You get your result and have the relationship in the other direction. It works without any hacking into ember-data as long you don't need caching, and if you need caching it requires the very few hacking I've done in my addon.
We still hope for ember-data to become fully JSONAPI complete, and that would require pagination. I think form an API perspective the best thing would be to have the ability to ask for the next and previous page on the ManyArray returned by the relationship. It would along with the JSONAPI where a next and previous link is provided. But to acomplish that now you would have to hack deep into ember-data without getting a big improvement over the top level .query, which I used successfully in many projects.
From the Ember.js guides on using models, you can also submit a query along with the find() call.
this.store.find('person', { name: "Peter" }).then(function(people) {
console.log("Found " + people.get('length') + " people named Peter.");
});
From the guide:
The hash of search options that you pass to find() is opaque to Ember
Data. By default, these options will be sent to your server as the
body of an HTTP GET request.
Using this feature requires that your server knows how to interpret
query responses.