Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - redirect to current url without one of the GET params

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.

like image 430
LAW Avatar asked Nov 19 '12 19:11

LAW


4 Answers

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
like image 195
dobrinov Avatar answered Nov 10 '22 20:11

dobrinov


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

like image 27
Eric C Avatar answered Nov 10 '22 20:11

Eric C


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&param2=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
like image 6
Lev Lukomsky Avatar answered Nov 10 '22 22:11

Lev Lukomsky


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:

  • Rails parameter parsing will automagically instantiate arrays and hashes for query params that use the special square bracket syntax: ?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.
  • The rails 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.
  • As such, the URL helpers like url_for are not much help.

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.

like image 2
Yetanotherjosh Avatar answered Nov 10 '22 21:11

Yetanotherjosh