Alejandra
Alejandra

Reputation: 726

Rails routes redirect for query string

I have a problem, recently the name of a controller changed.

I changed the routes file to accept calls using the old controller name, for people with bookmarks referencing the old name:

get '/old/about', to: redirect('/new/about')
get '/old/report/:client', to: redirect('/new/report/%{client}')
get '/old/:sub_path', to: redirect('/new/%{sub_path}')

that works fine. But for calls with query string it blocks it to /report/200. for example:

/old/report/200?c_id=257&end=2013-10-19&num_results=294540&start=2013-10-13

it cuts the url to:

old/report/200

and shows me an error because of the lack of parameters. Do you know what can I do? (I thought the :sub_path line in the routes would help but not) :(

Upvotes: 13

Views: 5284

Answers (4)

Michael Trojanek
Michael Trojanek

Reputation: 1943

The existing answers work perfectly, but are not quite suitable for keeping things DRY — there is a lot of duplicate code once you need to redirect more than one route.

In this case, a custom redirector is an elegant approach:

class QueryRedirector
  def call(params, request)
    uri = URI.parse(request.original_url)
    if uri.query
      "#{@destination}?#{uri.query}"
    else
      @destination
    end
  end

  def initialize(destination)
    @destination = destination
  end
end

Now you can provide the redirect method with a new instance of this class:

get "/old/report/:client", to: redirect(QueryRedirector.new("/new/report/#{params[:client]}"))

I have a written an article with a more detailed explanation.

Upvotes: 0

Eliot Sykes
Eliot Sykes

Reputation: 10063

Modify redirect to use the path: option to preserve the querystring:

- get '/old/about', to: redirect('/new/about')
+ get '/old/about', to: redirect(path: '/new/about')

This is demonstrated in the API docs for redirect, see http://api.rubyonrails.org/classes/ActionDispatch/Routing/Redirection.html#method-i-redirect

Upvotes: 21

ben
ben

Reputation: 1462

Building on Alejandra's answer, more verbose but without the ? if there's no query string:

get "/old/report/:client", to: redirect{ |params, request| ["/new/report/#{params[:client]}", request.query_string.presence].compact.join('?') }

So /old/report/:client?with=param will become /new/report/:client?with=param, and /old/report/:client will become /new/report/:client.

Upvotes: 3

Alejandra
Alejandra

Reputation: 726

The question mention by Matt helped me to figure out my answer (thanks a lot!). It was a slightly different for my specific case. Im leaving the answer that worked for me for future reference.

match "/old/report/:client" => redirect{ |params, request| "/new/report/#{params[:client]}?#{request.query_string}" }

Upvotes: 12

Related Questions