I'd like to generate a URL where the "p=1" query param appears at the end of the URL, like:
/path?foo=X&bar=Y&p=1
Is it possible to control the ordering of query parameters when generating URLs via:
url_for(params.merge({ p: page_num }))
?
Update:
I tried ChuckE's suggestion below. It turns out that in Ruby 1.9 Hashes are already ordered, so the code in ActiveSupport::OrderedHash
is effectively no-op'd. You can verify with Ruby 1.9 that order is preserved:
>> h = {one: 1, two: 2, three: 3 }
{:one=>1, :two=>2, :three=>3}
>> f = h.except(:one)
{:two=>2, :three=>3}
>> f[:one] = 1
1
>> f
{:two=>2, :three=>3, :one=>1}
However, url_for
still puts the "p" param first. It seems that any potential solution will need to address how url_for
iterates the hash.
After further digging, I see that what's happening is that url_for
is actually sorting the parameters by key lexicographically, independent of their insertion order in the hash. Apparently this is being done to aid caching, since URL params are often used for page cache keys.
In short, you can't do it without patching Hash
, specifically, you need to override activesupport/core_ext/object/to_param.rb
so that Hash#to_param does not call .sort
on the return value.
Related question: How to generate custom sorted query string URL in Rails link_to?.
First question is: why would you need something like that? The order which the parameters appear in the url in doesn't influence the way they are fetched by the server, since they are basic key/value associations. So, no matter where the parameter appears, it will always be recognized by the server.
Nonetheless, to answer your question, yes, it is possible. You just have to use ordered hashes. They are available through active support.
opts = OrderedHash.new
opts[:foo] = 'X'
opts[:bar] = 'Y'
opts[:p] = 1
your_helper_url(opts)
Should do the trick for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With