Ember dynamic query parameters - ember.js

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.

Related

Ember Data: When do I use findAll() over query()?

This is the pattern I find myself running into:
I start making an app, and I use findAll() to get a list of [something random].
Once the app is being tested with serious data, the number of random resource instances will grow. I need to limit the number of resource instances on screen. I need to start paginating them. For this I need query string support. E.g. page[offset].
So findAll(criteria) is replaced by query(criteria, querystring).
This is a pattern so much that findAll() is starting to look like a development placeholder for query() to be used later.
I'm probably misunderstanding the use for findAll(). Is it true findAll() cannot use pagination at all (without customizing adapter code)? Can someone explain in what cases findAll() should be used?
I personally use the findAll method for fetching data that appears in various drop-downs and short lists that cannot be filtered by the user. I use query and queryRecord for pretty much everything else.
Here are a couple of particularities of findAll that can be misleading:
findAll returns all of the records present in the store along with the data that is fetched using the record's adapter.
The return of findAll is two-fold, firstly you will receive the content of the store and then it will be refreshed with the data fetched using the adapter, this behavior can be overridden using the reload flag.
To expand on Jean's answer, findAll does just that, finds all! If you had entities such as "post types" where you have [advertisement, blog, poem], findall makes sense, because you are pulling these 3 things all the time (for example in a "post creator").
Query is more precise. Say You had an api returning every car you have ever seen.
Say you had a "car" model with properties "color" and "bodyStyle"
You could use:
// find all red cars -> /cars?color=red
store.query('car', {color: 'red'});
// find all cars that are coupes -> /cars?bodyStyle=coupe
store.query('car', {bodyStyle: 'coupe'});
To your question on pagination, this is typically implemented on the API. A popular pattern is to accept/return "page" and "count" properties. These are typically found in an API payload's "meta" property.
So if you wanted to look through all cars you know of/have in your database:
// find first 10 cars -> /cars?count=10&page=1
store.query('car', {count: 10, page: 1});
// on the next page, find the next 10 cars -> /cars?count=10&page=2
store.query('car', {count: 10, page: 2});
It is worth nothing that to further your own research you should look into query parameter binding on controllers to ease the labor needed to implement a solution like this.
https://guides.emberjs.com/release/routing/query-params/
In the examples in that link you can see how you can transition to routes and use the query parameters in your store requests to fetch relevant data.
In short, findAll() is great for finding a finite set of easy to represent information, typically types of entities.
query() is great for any filtered set of results based on a criteria, as you mentioned.
Happy Coding :)
If you want "all" record of a type I would recommend using query + peekAll, this is more or less what findAll does under the hood but without various timing issues / freshness issues that findAll is subject to.
query is generally a much better API because it lets you paginate, and most apps with data of any consequence eventually hit a point they are forced to paginate either for rendering concerns or data size concerns.

Clojure/Ring how to get post parameters in submit order

I have a very complex form. I need to get the post parameters from that form in the order they have been submitted. The application is created in ring/compojure.
All the parameters that I can get from ring request are preprocessed (grouped, sorted..)
How do I get the raw parameter list (preferably parsed to key/value vector or some other list)?
Could you provide more information about your project. What HTTP server are you using (http-kit, clj-http, aleph), and what middleware do you have applied in your project?
All parameter based things aren't actually part of the ring spec, but are handled by middleware (see https://github.com/ring-clojure/ring/wiki/Parameters), so it greatly depends on what bits you're currently pulling in.
I'm not aware of any ring middleware that currently exist that do you want, they all seem to parse the parameter list and put it into a hashmap, and if multiple parameters exist with the same key name, they make the value in the hashmap a vector of the items.
That all being said, I have to ask. Why do you need them in a particular order?
Your best option is to create your own middleware. Use the wrap-param middleware as a guide. You just need to do your custom stuff at https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/params.clj#L29
That said, I also be wary of expecting the params in a particular order as it will make brittle the client-server communication.

CFWheels: Redirect to URL with Params Hidden

I am using redirectTo() function with params to redirect to another pages with a query string in the url. For security purpose this does not look appealing because the user can change the parameters in the url, thus altering what is inserted into the database.
My code is:
redirectTo(action="checklist", params="r=#r#&i=#insp#&d=#d#");
Is there anyway around this? I am not using a forms, I just wish to redirect and I want the destination action/Controller to know what I am passing but not display it in the url.
You can obfuscate the variables in the URL. CfWheels makes this really easy.
All you have to do is call set(obfuscateURLs=true) in the config/settings.cfm file to turn on URL obfuscation.
I am sure this works with linkTo() function. I hope it works with RedirectTo() funcation as well. I do not have a set up to check it now. But if doesn't work for RedirectTo(), you can obfuscateParam() and deObfuscateParam() functions to do job for you.
Caution: This will only make harder for user to guess the value. It doesn't encrypt value.
To know more about this, Please read the document configuration and defaults and obfuscating url
A much better approach to this particular situation is to write params to the [flash].1 The flash is exactly the same thing as it is in Ruby on Rails or the ViewBag in ASP.Net. It stores the data in a session or cookie variable and is deleted at the end of the next page's load. This prevents you from posting back long query strings like someone that has been coding for less than a year. ObfuscateParam only works with numbers and is incredibly insecure. Any power user can easily deobfuscate, even more so with someone that actually makes a living stealing data.

Removing query string from url in django while keeping GET information

I am working on a Django setup where I can receive a url containining a query string as part of a GET. I would like to be able to process the data provided in the query string and return a page that is adjusted for that data but does not contain the query string in the URL.
Ordinarily I would just use reverse(), but I am not sure how to apply it in this case. Here are the details of the situation:
Example URL: .../test/123/?list_options=1&list_options=2&list_options=3
urls.py
urlpatterns = patterns('',
url(r'test/(P<testrun_id>\d+)/'), views.testrun, name='testrun')
)
views.py
def testrun(request, testrun_id):
if 'list_options' in request.GET.keys():
lopt = request.GET.getlist('list_options')
:
:
[process lopt list]
:
:
:
:
[other processing]
:
:
context = { ...stuff... }
return render(request, 'test_tracker/testview.html', context)
When the example URL is processed, Django will return the page I want but with the URL still containing the query string on the end. The standard way of stripping off the unwanted query string would be to return the testrun function with return HttpResponseRedirect(reverse('testrun', args=(testrun_id,))). However, if I do that here then I'm going to get an infinite loop through the testrun function. Furthermore, I am unsure if the list_options data that was on the original request will still be available after the redirect given that it has been removed from the URL.
How should I work around this? I can see that it might make sense to move the parsing of the list_options variable out into a separate function to avoid the infinite recursion, but I'm afraid that it will lose me the list_options data from the request if I do it that way. Is there a neat way of simultaneously lopping the query string off the end of the URL and returning the page I want in one place so I can avoid having separate things out into multiple functions?
EDIT: A little bit of extra background, since there have been a couple of "Why would you want to do this?" queries.
The website I'm designing is to report on the results of various tests of the software I'm working on. This particular page is for reporting on the results of a single test, and often I will link to it from a bigger list of tests.
The list_options array is a way of specifying the other tests in the list I have just come from. This allows me to populate a drop-down menu with other relevant tests to allow me to easily switch between them.
As such, I could easily end up passing in 15-20 different values and creating huge URLs, which I'd like to avoid. The page is designed to have a default set of other tests to fill in the menu in question if I don't suggest any others in the URL, so it's not a big deal if I remove the list_options. If the user wishes to come back to the page directly he won't care about the other tests in the list, so it's not a problem if that information is not available.
First a word of caution. This is probably not a good idea to do for various reasons:
Bookmarking. Imagine that .../link?q=bar&order=foo will filter some search results and also sort the results in particular order. If you will automatically strip out the querystring, then you will effectively disallow users to bookmark specific search queries.
Tests. Any time you add any automation, things can and will probably go wrong in ways you never imagined. It is always better to stick with simple yet effective approaches since they are widely used thus are less error-prone. Ill give an example for this below.
Maintenance. This is not a standard behavior model therefore this will make maintenance harder for future developers since first they will have to understand first what is going on.
If you still want to achieve this, one of the simplest methods is to use sessions. The idea is that when there is a querystring, you save its contents into a session and then you retrieve it later on when there is no querystring. For example:
def testrun(request, testrun_id):
# save the get data
if request.META['QUERY_STRING']:
request.session['testrun_get'] = request.GET
# the following will not have querystring hence no infinite loop
return HttpResponseRedirect(reverse('testrun', args=(testrun_id,)))
# there is no querystring so retreive it from session
# however someone could visit the url without the querystring
# without visiting the querystring version first hence
# you have to test for it
get_data = request.session.get('testrun_get', None)
if get_data:
if 'list_options' in get_data.keys():
...
else:
# do some default option
...
context = { ...stuff... }
return render(request, 'test_tracker/testview.html', context)
That should work however it can break rather easily and there is no way to easily fix it. This should illustrate the second bullet from above. For example, imagine a user wants to compare two search queries side-by-side. So he will try to visit .../link?q=bar&order=foo and `.../link?q=cat&order=dog in different tabs of the same browser. So far so good because each page will open correct results however as soon as the user will try to refresh the first opened tab, he will get results from the second tab since that is what is currently stored in the session and because browser will have a single session token for both tabs.
Even if you will find some other method to achieve what you want without using sessions, I imagine that you will encounter similar issues because HTTP is stateless hence you will have to store state on the server.
There is actually a way to do this without breaking much of the functionality - store state on client instead of server-side. So you will have a url without a querystring and then let javascript query some API for whatever you will need to display on that page. That however will force you to make some sort of API and use some javascript which does not exactly fall into the scope of your question. So it is possible to do cleanly however that will involve more than just using Django.

How do I retrieve Haystack SearchQuery parameters

I am looking for a way to serialize a Haystack search query (not the query results) so that I can reconstruct it later. Is there a way to do this without having to intercept the parameters from off of the request object?
For context, I want users to be able to subscribe to the results of a particular search, including any new results that may pop up over time.
Edit:
I settled on storing the search with:
filter = queryset.query.query_filter
and then loading this back in using:
SearchQuerySet().raw_search(filter)
Though I suspect this will tie me to whichever particular search back-end I'm using now. Is this true? Is there a better way?
You should have the query in your request.GET. Then it should be fairly easy to construct a RSS Feed using that query.