Ruby On Rails - Use "Format" As A URL GET Parameter? - ruby-on-rails

I have a search page where I update the URL params on the page as filters are added or removed by the user. This allows me to deep link into the page (ie. going to /search?location=new+york&time=afternoon will set the location and afternoon filters).
I also have a filter named format. I noticed that passing in ?format=whatevervalue to the URL and then reloading the page with that param causes Rails to return a Completed 406 Not Acceptable error. It seems that format is a reserved Rails URL parameter.
Is there anyway to unreserve this parameter name for a particular endpoint?

In the context of an URL in Ruby on Rails there are at least four reserved parameter names: controller, method, id, format.
You cannot use these keys for anything else than for their intended purpose.
If you try to you will override the value internally set by Rails. In your example by setting ?format=whatevervalue you override the default format (html) and your application will try to find and render a whatevervalue template instead of the html formatted template. This will obviously not work.
Fun fact: Instead of using the default Rails path format like /users/123/edit you could use query parameters instead like this: /?controller=users&id=123&method=edit&format&html.
My suggestion is: Do not try to fight Rails conventions. Whenever you try to work around basic Rails conventions it will hurt you later on because it makes updates more difficult, common gems might break, unexpected side-effects will happen. Just use another name for that parameter.

Related

Symfony linking to an admin Table record edit page

kind of finding it difficult to wrap my head around this. For those who have used the Symfony admin generator extensively, for each module based of a backend module, there is an edit page for all the records. Typically this can be accessed like this:
module/primarykey/edit. (assume questions/1/edit)
which is strange because typically the primary key would be passed in as a URI parameter like:
questions/edit/1. Anyways, that maybe irrelevant. What is important is how do I manage to generate a link_to for the above URI. I am linking the editSuccess page through an external page which does not belong to the UI. The syntax I use is
link_to('Edit','questions/'.$primary_key.'/edit') // (where $primary_key = 1 as in this case)
However that auto modifies itself to :
/backend_dev.php/questions/1/action note the action instead of edit
No such action exists and it returns a 404 error stating that questions/action does not exist
To summarize, How do you link to an admin page that renders specifically for a record?
The url_for (and thus the link_to) helpers deal with internal urls, not external ones. The syntax is module/action?parameters. In your case this would be question/edit?id=$primarykey (assuming the action looks for the id parameter).
If you give a name to your route, that makes generating the link faster (hashtable lookup vs. linear search):
echo url_for("#question_edit?id=$primary_key");
If you set up your route as an sfDoctrineRoute, it gets even simpler:
echo url_for("question_edit", $question);
note how you need not pass the id, but the question object - the route class will fetch all neccessary parameters.

Rails 3 - Friendly params in url (GET)

I have a rails 3 app and now i implementing filter for my catalog. Filters form pass data to controller through GET request. As a result i have link like this in my browser after i submit
my form (apply search):
http://localhost:3001/shoes?filter%5BShoeBottomType%5D%5B%5D=2&filter%5BShoeClassification%5D%5B%5D=1&filter%5BShoeClassification%5D%5B%5D=2&filter%5BShoeElation%5D%5B%5D=3&filter%5BShoeElation%5D%5B%5D=4&filter%5BShoeElation%5D%5B%5D=5&filter%5BShoeLiningColor%5D%5B%5D=2&filter%5BShoeLiningColor%5D%5B%5D=3&filter%5BShoeLiningColor%5D%5B%5D=4&filter%5BShoeTopColor%5D%5B%5D=1&filter%5BShoeTopColor%5D%5B%5D=2&filter%5Bonly_action%5D%5B%5D=1&page=2
Is there a way to do URL more beautiful?
PS i dont want use POST request, because I read that it is bad for SEO
TLDR: just leave it.
HTML forms serialize in a straightforward manner; the parameters are named after the HTML elements. The actual issue here is how the form elements are named. It looks like they have names like filter[ShoeBottomType][]; look into your HTML to see the name attributes. Since you're in Rails, I'm guessing you having a filter hash passed to your Rails controller method as a single argument, and since Rails expects hashes to use a certain URL format for hashes and arrays (it has to know how to deserialize it from the request), the form helper writes the form that way. And yours is especially complicated because the hash values are arrays, hence the extra set of brackets. Then it's URL encoded and you end up with an ugly mess.
You could avoid some of this problem by passing the inputs individually back to the controller instead of as a big hash. Something like:
def index
shoe_bottom_types = params[:bottom_types]
shoe_classifications = params[:classifications]
shoe_elations = params[:elations]
...
which will get you to: /shoes?bottomTypes[]=1&bottomTypes[]=2.... That doesn't seem much better, and now your controller is all gross. And I don't see how you're going to get rid of the brackets entirely if you want to have more than one of the same filter. I guess you could get crazy and do your own parsing in your controller, like breaking apart shoeBottomTypes=1|2, but then you'll have to do your own form serialization too. Again, just not worth it.
Backing up for a sec, the SEO stuff doesn't make much sense. Search engines won't fill out your form; they just follow links. The real reason you should use GET is that (presumably), submitting your form doesn't have side effects, since it's just a search. See here; it's important to use the right HTTP methods. If you use POST, you'll get weird warnings on reloads and you won't be able to bookmark the search.
Backing up even further, why do you care, especially now that SEO is out of the picture? Just as a quick demo, I did a google search for the word "thing" and this was the URL:
https://www.google.com/#hl=en&output=search&sclient=psy-ab&q=thing&pbx=1&oq=thing&aq=f&aqi=g2g-s1g1&aql=1&gs_sm=3&gs_upl=764l1877l0l1980l6l6l0l0l0l0l89l432l5l5l0&bav=on.2,or.r_gc.r_pw.r_cp.r_qf.,cf.osb&fp=220ef4545fdef788&biw=1920&bih=1086
So URLs for form submissions can be long. The user won't even look at it.
The only possibility I can think of for why you'd care about the length/ugliness of your URL here is that you want, separately from the form, to create links to certain searches. There are several ways to handle that, but since I don't know whether that's relevant to you, I'll let that be a follow-up.
So bottom line, it looks like I'd expect, and trying to fix it sounds ugly and pointless.
If you do not want to use a POST request, then there is no other way then to put the form values in the URL -- they have to get to the server one way or another.
On the other hand however, I do not see why doing a POST would be bad for SEO and I would love to see the article that stated so.
My suggestion is that you could add some custom routes to beautify your urls.
For example :
http://localhost:3001/shoes/Type/2/Classification/1,2/Elation/3,4,5/LiningColor/2,3,4/TopColor/1,2/only_action/1/page/2
This is far much shorter than your initial URL ;)
The counterpart is that, as far as I know, you have to use always the same order for params in your url.
The routing rule is the following :
match "shoes/Type/:type/Classification/:classification/Elation/:elation/LiningColor/:liningcolor/TopColor/:topcolor/only_action/:only_action/page/:page" => "shoes#show"
You can retrieve the passed values in params array. You have to split the string containing , in order to retrieve the multiple values.

rails, cannot get params from url

I'm trying to use Google Federated Login REST API. I can succesfully reach out to the google server and validate a user but I cannot pull parameters from the return url
for example:
http://mysite.com/login/return?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.op_endpoint=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fud...
All the variables in that return string are not accessible in the params array. I have no idea how to get them out. requst.url, request.query_parameter, and all similar calls do not return the query string.
I think i found the issue. I was using the open-uri library to make the call to google's endpoint url so it may have been stepping outside of the normal rails response/request cycle. I've since used Net::HTTP requests and parse the information from the response.
So I have a very similar issue, where I'm actually building a Rails-based openid provider but being consumed by another Rails app. I basically adapted the code from
The whole URL was:
http://localhost:3000/openid?openid.assoc_handle=%7BHMAC-SHA1%7D%7B5193d33f%7D%7BdBrUwQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3000%2Fopenid%2Fwarren&openid.identity=http%3A%2F%2Flocalhost%3A3000%2Fopenid%2Fwarren&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1&openid.realm=http%3A%2F%2Flocalhost&openid.return_to=http%3A%2F%2Flocalhost%2Fsession%3F_method%3Dpost%26return_to%3D&openid.sreg.required=nickname%2Cemail
I had a similar problem where the only parameters being reported were:
{"action"=>"index", "controller"=>"openid"}
So, suspecting that some parameter (maybe a period?) was causing it to hiccup, I went through and deleted them one by one until I found that deleting the following parameter enables the entire thing to go through correctly:
openid.mode=checkid_setup
That left all the remaining parameters correctly being parsed:
{"openid.assoc_handle"=>"{HMAC-SHA1}{5193d33f}{dBrUwQ==}",
"openid.claimed_id"=>"http://localhost:3000/openid/warren",
"openid.identity"=>"http://localhost:3000/openid/warren",
"openid.ns"=>"http://specs.openid.net/auth/2.0",
"openid.ns.sreg"=>"http://openid.net/extensions/sreg/1.1",
"openid.realm"=>"http://localhost",
"openid.return_to"=>"http://localhost/session?_method=post&return_to=",
"openid.sreg.required"=>"nickname,email",
"action"=>"index",
"controller"=>"openid"}
I'm now trying to find why openid.mode causes this issue. It fails even if I change it to openid.mode=5, so it's the key, not the value, causing the problem.
Suspecting the ".mode" part of the string for the trouble (maybe ".mode" is a filetype or something being parsed by the routing?) I am looking towards this post on allowing periods, but it only applies to the value, not the key: rails routing and params with a '.' in them
Will report back if I find more.
Update: I tried, in another Rails app, adding ?openid.mode=0 to the end of a URL -- ".mode" does not result in a parameter being read, but ".modes=" does and so does ".mod=". This confirms that ".mode" is causing a params parsing error.
Update 2: yikes... actually "?a.mode=0" does work. So far, only the complete string "openid.mode" does not work, and this is across various Rails apps. "?openid.mode" with nothing else results in: Parameters: {"openid.mode"=>nil}, but "?openid.mode=" with nothing after the "=" fails to pass any parameters besides action & controller. Very odd.
Update 3: OK, figured it out, I believe -- the params were getting sanitized i.e. deleted by the rack-openid gem, in that gem's path: /lib/openid.rb:168, "sanitize_query_string". This seems to be incompatible with the example I was working with: https://github.com/openid/ruby-openid/tree/master/examples/rails_openid. Going to override that method.
Final update: I replaced this line:
oidreq = server.decode_request(params)
with this line, since we could no longer use the now-empty params hash:
oidreq = server.decode_request(Rack::Utils.parse_query(request.env['ORIGINAL_FULLPATH']))

How do you change the default format to XML in Symfony?

I'm writing a restful XML API for a university assignment, the spec requires no HTML frontend.
There doesn't seem to be any documentation (or guessable functionality) regarding how to change the default format? Whilst thus far I have created all templates as ...Success.xml.php it would be easier to just use the regular ones and set this globally; I really expected this functionality to be configurable from YAML.. yet I have found some hard coded references to the HTML format.
The main issue I'm encountering is that part of the assessment is returning a 404 in a certain way (not as a 404 :/), but importantly it must always return XML, and the default setup of a missing route is a HTML 404 not XML (so it only works when I use forward404 from an action running via a XML route.
So in summary, is there a way to do this / what class(es) do I have to override?
Try putting this in factories.yml
all:
request:
class: sfWebRequest
param:
default_format: xml
That will still need the template names changing though. It will just mean that urls that don't specify a format will revert to xml instead of html.
You can subclass sfPHPView and override the initialise method to affect this (copy paste the initialise method from sfView) - the lines like this need changing:
if ('html' != $format)
You then need to change the view class used ... try this:
http://mirmodynamics.com/post/2009/02/23/symfony%3A-use-your-own-View-class

How to access AJAX hash values in ASP.NET MVC?

I'm considering using the hash method to create static urls to content that is managed by ajax calls in a Asp.Net MVC. The proof of concept i'm working on is a profile page /user/profile where one can browse and edit different sections. You could always ask for the following url /user/profile#password to access directly to you profile page, in the change password section
However, i'm wondering if i'm not starting this the bad way, since apparently i can't access the part after the hash in any way, except by declaring a route value for the hash in global.asax. So i'm wondering if this is the right way to access this part of the url?
Am i supposed to declare a route value, or is there another way to work with hash values (a framework, javascript or mvc)?
Edited to add:
In pure javascript, i have no problem using the window.location.hash property, i'm not sure though how standard it is in today's browsers, hence the question about a javascript framework/plugin that would use it.
The thing is that the part that follows the hash (#) is never sent to the server into the HTTP request so the server has absolutely no way of reading it. So no need to waste time in searching for something that doesn't exist.
You could on the other hand tune your routes to generate links that contain the hash part so that client scripts can read it.
Send the hash value document.location.hash as a parameter to the controller action of your choice.
This can be done in the code if needed...
RedirectResult(Url.Action("profile") + "#password");
should work fine

Resources