The cloudant RESTful API is fairly simple but doesn't match the way ember-data expects things to be. How can I customize or create an Adapter that deals with these issues...
In my specific case I only want to load records from one of several secondary indexes (ie. MapReduce fnctions).
The URL for this is below, where [name] and [view] would change depending on user selection or the route I am in.
https://[username].cloudant.com/[db_name]/_design/[name]/_view/[view]
Looking at the ember-data source there doesn't seem to be an easy way of defining URLs like this. I took a look at findQuery and it expects to send any variables through as url params not as part of the actual URL itself.
Am I missing something? Is there an obvious way of dealing with this?
Then the data comes back in a completely different format, is there a way to tell ember what this format is?
Thanks!
I had similar problem where URL's are dynamic. I ended up creating my own adapater by extending DS.RESTAdapter and overriding the default buildURL method. For example:
App.MyAdapter = DS.RESTAdapter.extend({
buildURL: function(record, suffix) {
var username, db_name, name, view;
// Do your magic and fill the variables
return 'https://'+username+'.cloudant.com/'+db_name+'/_design/'+name+'/_view/'+view;
}
});
I ended up also defining my own find, findAll, findQuery, createRecord, updateRecord, deleteRecord etc. methods as I had to pass more variables to buildURL method.
If returning data is in different format then you can also write your own serializer by extending DS.JSONSerializer and define your own extraction methods extract, extractMany etc.
You should evaluate how well your API follows the data format required by ember/data RESTAdapter. If it is very different then it's maybe better to use some other component for communication like ember-model, ember-restless, emu etc, as ember-data is not very flexible (see this blog post). You can also write your own ajax queries directly from routes model hooks without using ember-data or other components at all. It is not very hard to do that.
Related
I set up a simple Ember Twiddle to show you my error that is occurring when trying to update a model.
It's considerable that I'm using ember-cli-mirage for mocking the data.
According to the docs, I created a shorthand route that should handle the PUT request.
It does, but with the error: Your handler for the url /api/shops/1 threw an error: Cannot convert undefined or null to object
When using the JSONAPISerializer, everything is working with shorthands (mirage/config.js) and I'm able to update models, but in my case I have to use the RESTSerializer with serialized IDs in the responses.
The request payload when I'm sending the model's attrs are without Id at the end of the property name, f.e.:
// attrs object in PUT request
{
name: "Shop 1",
city: "1" // belongsTo relationship,
}
Now Mirage is trying to find those properties on the respective database model that has to be updated, but cannot find it, because in the database it's cityId and not just city...
I also found this issue report and it’s working, but I was hoping I could avoid something like this. As far as I can remember, in previous versions of ember-cli-mirage (v0.1.x) it was also not needed to override the normalize method in the serializer to be able to make use of the RestSerializer with serializedIds…
My question is:
Is there a way to stick to shorthand route handlers only, or do I really have to write a helper or other custom solution only because I have to use the RestSerializer?
That would be really sad, but at least I would know then.
Thanks for your support!
Short answer: it looks like you need the custom serializer for now until the bug fix for it is merged.
Long answer: that issue looks to be an issue that occurred in the 0.2 -> 0.3 upgrade for Mirage, likely because of underlying DB changes made in Mirage. It'll probably get fixed, but for now you'll need to work around it.
I defined the queryParams in the controller and I need to add additional query parameters which is not used in the Ember application and it can have any name. It's an analytics thing. Those query parameters are not known in advance thus, we are not able to define those analytics values in the queryParams property. What happens now is Ember deletes all additional parameter after the queryParams and URL binding is triggered.
Example:
In the Controller:
queryParams: ['fin', 'ftw'],
fin: null,
ftw: null,
url:
localhost:3000?fin=111&ftw=121&anatylicsvalue=1
when I change the value of fin or ftw, anatylicsvalue is removed. I need the app to retain that bit of string.
What is the best way of doing this?
You need to define analyticsvalue within queryParams array of the controller, or queryParams json object of the router whether or not it is going to be used by the controller. So, if you declare queryParams as ['fin', 'ftw', 'analyticsvalue'] it will retain.
In order to achieve a somewhat dynamic query parameter (where even the name of the parameter is not known in advance), the only option I can suggest is using a named query parameter and using JSON.stringify to put the query parameters with that name. Take a look at the following twiddle. index.js route defines queryParams as queryParams: ['fin', 'ftw', 'additionalParams'] and additionalParams query parameter holds dynamic parameters since it is a JSON object that can hold any dynamic sub-parameter. Take a look at the updateAdditionalParams inside actions it defines a dynamic property and dynamic values as you can see.
Unfortunately, Ember does not support custom query parameters that are not known in advance. You can use the approach I have illustrated in the twiddle. Hope this helps.
Unfortunately, Ember does not support custom query parameters that are not known in advance.
It's a shame there's no "remainder" capability, if I understand what you're saying correctly. If an SPA was called with the requirement that any query parameters that it does not understand must be passed through verbatim on all its outgoing URLs, the SPA would need to scrape these off itself during routing, outside the Ember mechanisms? Do I have this right?
With controllers going away, will all of the query parameter support end up on the route? Is there something we should be doing to "future-proof" our design now?
Currently my Ember-cli application calls my API in this way:
apiurl:3000/ingredients?name=something
apiurl:3000/ingredients?filter=som?limit=10
I'd like to make Ember query for:
apiurl:3000/ingredient/something
apiurl:3000/ingredients/som?limit=10
But I've two problems:
WARNING: Encountered "ingredients" in payload, but no model was found for model name "ingredient" (resolved model name using myapp#serializer:application:.modelNameFromPayloadKey("ingredients"))
I can't find a way to make Ember use URL segments instead of query parameters.
I think I'm missing something?
Have you looked into overriding your RESTAdapter's buildURL method?
http://emberjs.com/api/data/classes/DS.RESTAdapter.html#method_buildURL
As what you're trying to do appears to be quite specific you could use this method to override the building of these requests, while at the same time keeping the default Ember model/params implementation the same.
I have what I believe to be common but complicated problem to model. I've got a product configurator that has a series of buttons. Every time the user clicks on a button (corresponding to a change in the product configuration), the url will change, essentially creating a bookmarkable state to that configuration. The big caveat: I do not get to know what configuration options or values are until after app initialization.
I'm modeling this using EmberCLI. After much research, I don't think it's a wise idea to try to fold these directly into the path component, and I'm looking into using the new Ember query string additions. That should work for allowing bookmarkability, but I still have the problem of not knowing what those query parameters are until after initialization.
What I need is a way to allow my Ember app to query the server initially for a list of parameters it should accept. On the link above, the documentation uses the parameter 'filteredArticles' for a computed property. Within the associated function, they've hard-coded the value that the computed property should filter by. Is it a good idea to try to extend this somehow to be generalizable, with arguments? Can I even add query parameters on the fly? I was hoping for an assessment of the validity of this approach before I get stuck down the rabbit hole with it.
I dealt with a similar issue when generating a preview popup of a user's changes. The previewed model had a dynamic set of properties that could not be predetermined. The solution I came up with was to base64 encode a set of data and use that as the query param.
Your url would have something like this ?filter=ICLkvaDlpb0iLAogICJtc2dfa3
The query param is bound to a 2-way computed that takes in a base64 string and outputs a json obj,
JSON.parse(atob(serializedPreview));
as well as doing the reverse: take in a json obj and output a base64 string.
serializedPreview = btoa(JSON.stringify(filterParams));
You'll need some logic to prevent empty json objects from being serialized. In that case, you should just set the query param as null, and remove it from your url.
Using this pattern, you can store just about anything you want in your query params and still have the url as shareable. However, the downside is that your url's query params are obfuscated from your users, but I imagine that most users don't really read/edit query params by hand.
I'm trying to migrate my app to the new emberjs routing API.
With old router I had some workarounds to provide similar URI for objects saved by ID and for new objects which described by set of params. This were done for ability of exchange links to objects between users without permanently saving it. This is two simplified valid routes from my app:
/objects/12 // fetch object by id (/objects/:object_id)
/objects/<serialized params> // build new object from params (/objects/:params)
Both of this routes are similar to router because they all have dynamic parts and static parts are equal. So I wrote custom RouteMatcher to pickup right route. Lack of query string parsing forced me to do this hack as quick and semilegal solution, also there is ancient ticket about this feature on github.
With the new router matching has been extracted to separate package (route-recognizer) so I cannot do the trick (or it will be full of hacks and injections).
As I can see I have to choose from these options:
Totally rewrite my URIs and separate all intersecting routes
Rewrite URIs but try to implement query string parser for the new Ember.Router
Put all logic into one route and reimplement only serialize/deserialize methods (something dirty)
Second solution seems to be more clean.
What will be the best non complicated decision? Should I try to find another way?
The current router does not support query-string parameters.
We are tracking this bug at https://github.com/emberjs/ember.js/issues/1773. You may want to follow it.
In the meantime, your best bet is probably to use a dynamic segment and manually serialize (with the serialize hook) and deserialize (with the model hook).