I have a very simple problem in a Rails app that I can't find an elegant solution to.
I have a URL like: http://www.example.com/some-path/?foo=123&baz=456
And I want to process one of the params and do a redirect to: http://www.example.com/some-path/?baz=456
I want this to work generally for any URL with param "foo", so I don't want to specify "baz" in the rewrite code.
What I want is something like:
redirect_to request.path, :params => request.query_parameters.except(:foo)
Except that doesn't quite work. I know I can regex or parse the query string manually but I assume there's a better way.
The best way which I have found so far is to use:
url_for(params.except(:obsolete_param_name))
UPDATE
As grosser mentioned this opens up a security hole in your application as an attacker can pass a host as a url param and redirect the user to a different website. In order to prevent this you can use rap1ds's suggestion and specify that only the path has to be used.
You can use a helper function like this one for this purpose:
def secure_path_for(params, *excluded_params)
url_for(params.except(*excluded_params).merge(only_path: true))
end
What about just deleting params[:foo] before you pass it along. Maybe something like:
params.delete[:foo]
redirect_to request.path, :params => params
It's not really elegant, but it only adds one line. Params by the way is a helper method that get's the url's current parameters
In rails 5 you will get non-sanitized request parameters error if you attempt to do this url_for(params.except(:param))
So I found this way to do this:
request_url = request.url # eg. http://qwe.com/path?param1=1¶m2=2
query_hash = Rack::Utils.parse_query(URI.parse(request_url).query).except('param1')
url = query_hash.empty? ? request.path : "#{request.path}?#{query_hash.to_query}"
puts url #=> /path?my_param2=2
redirect_to url
uri = URI.parse(request.url)
new_query = uri.query.split("&").reject{|pair|
k,v = pair.split("=")
k =~ /^foo\[?/ # reject params named "foo" or "foo[anything"
}.join("&")
# if the new querystring is empty, assign nil instead of "" so we don't
# end up with a solitary question mark at the end of the url.
uri.query = (new_query.empty? ? nil : new_query)
redirect_to uri.to_s
I came to the above solution after running into some non-obvious problems with trying to do things the "Rails way," if there is such a way, to solve this issue. For instance:
?x[a]=1&y[]=2
becomes {"x"=>{"a"=>"1"}, "y"=>["2"]}
and so on, so code that uses the provided querystring and param routines are tricky to deal with in this regard. And filtering params by raw string value can be difficult as a result. Even the non-rails/rack CGI module will give you arrays instead of strings for the param values.params
hash includes both GET, POST, and routing parameters, such as :action
and :controller
so you couldn't just re-use that to reconstruct a querystring anyway.Given these issues I found I was not able to use provided framework functionality to get a pure and unmolested querystring, reproduced as-is from the current request, that simply and only removes one parameter. The code above seems to work well, however.
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