bess
bess

Reputation: 223

Rails route redirect using both constraints and a block?

I am writing a replacement system for a legacy application, and we want the old URLs to redirect to the new URL structure. I would like to use the redirect helper in routes.rb to accomplish this. This works great for simple cases. However, there are some legacy identifiers that contain dots. If an identifier contains a dot I need to:

  1. Not lose the second half of the identifier
  2. Replace the dot with a dash

So, here is my test for this in rspec:

    it "redirects requests correctly when there are dots in the eadid" do
      get "/collections/MC001.02.01/c00003"
      expect(response.code).to eq "301"
      expect(response).to redirect_to("http://www.example.com/catalog/MC001-02-01_c00003")
    end

I have read the documentation for the redirect helper in several places. I see that I can use constraints to correctly grab the entire id, in spite of the dots. So, this works for grabbing the entire id:

get "/collections/:eadid/:componentid", to: redirect("/catalog/%{eadid}_%{componentid}"), constraints: { eadid: /([^\/])+?/ }

This returns /catalog/MC001.02.01_c00003. Close, but not quite right, because I also need to replace the dots with dashes.

I also see that I can use a block format if I need to do some more complicated logic, e.g., string replacement, like this:

  get "/collections/:eadid/:componentid", to: redirect { |params, request|
    "/catalog/#{params[:eadid].gsub('.','-')}_#{params[:componentid]}"
  }

This doesn't work, because the bit of the eadid after the first dot has been dropped, as I can see if I examine both the params and the request:

"action_dispatch.request.path_parameters"=>{:eadid=>"C0140", :componentid=>"c03411"}

I have not been able to find an example of a redirect helper configured to use both a constraint and a block. Guesses at syntax have not been fruitful. Anyone know the secret formula here? Or is there a better approach for what I'm trying to do?

Thank you!

Sources consulted:

Upvotes: 3

Views: 781

Answers (2)

bess
bess

Reputation: 223

I ended up going with this, because I find it slightly easier to read, but I can confirm that Geoffroy's answer works and I've marked it as accepted.

  get "/collections/:eadid/:componentid", constraints: { eadid: /([^\/])+?/ }, to: redirect { |params, _request|
    "/catalog/#{params[:eadid].tr('.', '-')}_#{params[:componentid]}"
  }

Geoffroy's suggestion to list out what syntax guesses I had made already was also very helpful. Thank you!

Upvotes: 4

Jaffa
Jaffa

Reputation: 12719

You have to take care with the similar (but different) syntax between blocks and hashes

This is the syntax for one-line blocks:

redirect {|params, request| ...}

This is the syntax for a Hash:

{to: redirect("/catalog/%{eadid}_%{componentid}")}

The { and closing } are optional when the Hash is the last argument to a method call, as is the case with your get.

Now if you want to mix boths, you may need to take good care of what you're doing.

Another solution would be to extract the constraint:

constraints(eadid: /[^\/]+/) do
  get "/collections/:eadid/:componentid", to: redirect { |params, request|
    "/catalog/#{params[:eadid].gsub('.','-')}_#{params[:componentid]}"
  }
end

Upvotes: 4

Related Questions