Escaping elements in a URI Ruby On Rails - ruby-on-rails

I have a rails app that I am trying to do a get request with co-ordinates in...
I have a route in my routes.rb like this:
map.connect 'feeds/get/:location', :controller => "feeds", :action => "get"
I can send a string consisting of alphanumeric characters fine, but I need to send co-ordinates in a string in the URI as a get request:
51.896834,0.878906.
So, I escaped the string like so, and append it to my URI.
http://thisisnottheurl.net/feeds/get/51%2E896834%2C0%2E878906.xml
however it looks like rails automatically unescapes the string before the controller and gives me this routing error in the log:
ActionController::RoutingError (No route matches "/feeds/get/51.896834,0.878906.xml" with {:method=>:get}):
How do I stop rails escaping this string (with routes?) so that it can be read in the controller?
I looked at using the match function in routes.rb with regex, but that is rails 3 only...

The only real way I can think of doing this would be as follows, give the route a name as follows:
map.connect 'feeds/get', :controller => "feeds", :action => "get", as: 'get_feeds'
Then you would have a named route helper get_feeds_path, which you could then pass in location and a format as follows:
get_feeds_path(:location => '51.896834,0.878906', :format => 'xml')
What might be an even better idea however, is if you passed in two params, one for each of the coordinates.
get_feeds_path(:x_location => '51.896834', :y_location => '0.878906', :format => 'xml')
Then, the params hash passed to the controller should have a params[:x_location] and a params[:y_location] which you can manipulate to your liking.

Related

Rails Routing having a URL in the query string

So I need to hit a url like mydomain.com/proxies/www.msn.com in order to fulfill some ajax requests for an API
In my route I have
get "/proxies/:url" => "proxies#get"
and I in the controller I have
url_contents = Net::HTTP.get(URI.parse(params[:url]))
which if i put /proxies/www i get
undefined method `request_uri' for #<URI::Generic:0x3f89508 URL:www>
if i put /proxies/www.msn.com
I get
No route matches [GET] "/proxies/www.msn.com"
You have two separate problems here:
You're trying to treat a URL without a scheme as an HTTP URL.
Your /proxies route won't match :urls with dots and slashes the way you're expecting it to.
For the first one, you'll have to add the schema manually:
url = 'http://' + params[:url]
content = Net::HTTP.get(URI.parse(url))
For the second one, you can use a splat-route to deal with embedded slashes and :format => false to keep Rails from trying to treat .com, for example, as a format:
get '/proxies/*url' => 'proxies#get', :format => false
If you use :url, Rails will see embedded slashes as component separators and that's probably not what you want. Without the the :format => false, Rails will try to interpret .X (for any X) as a format (just like .html, .json, ...) rather than as part of the URL.
This is applicable for rails-2
The problem is with the dot(.) I guess. Ive tried something like below and it worked.
#routes.rb
map.get_proxy 'proxies/:url', :controller => "Proxies", :action => "get", :requirements => { :url => /.*/ }
#view file
#Here dot(.) are needed to replace with its encoded string %2E
<%= link_to 'Get The Site', get_proxy_url('www.msncom') %>
#Proxies Controller
#After receiving the url the %2E need to conovert to dot(.) again.
url_contents = Net::HTTP.get(URI.parse('http://'+params[:url]))
modified as stated by #mu.
match '/proxies/:url' => 'proxies#get', :as => :proxies_get

rails: avoid string escaping in route parameters

i have a route defined like this
map.search_by_key '/search/:search_key', :controller => 'my_controller', :action => 'my_action'
the param :search_key is used such that the urls are like this:
mysite.com/search/c_vehicles/c_cars/mk_suzuki
where search_key would be "c_vehicles/c_cars/mk_suzuki" ..
problem is .. when creating this url with the named route
search_by_key_path("c_vehicles/c_cars/mk_suzuki") it escapes the string .. and creates something like:
mysite.com/search/c_vehicles%2Fc_cars%2Fmk_suzuki
this works fine but looks ugly in the address bar .. how do i avoid this ..
I'm using rails 2.2.2 with ruby 1.8.6 (ancient i know .. in process to upgrade) ..
ideas?
You can use a globbed route for this and a bit of string wrangling in your controller:
Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example
map.connect 'photo/*other', :controller => 'photos', :action => 'unknown'
This route would match photo/12 or /photo/long/path/to/12 equally well, creating an array of path segments as the value of params[:other].
Your route should look like this:
map.search_by_key '/search/*search_key', :controller => 'my_controller', :action => 'my_action'
#--------------------------^ Change the colon to an asterisk
And then in your controller:
def my_action
search_for = params[:search_key].join('/')
# ...
end
The same globbing technique applies equally well in Rails-3 so upgrading this part of your application should be a simple matter switching to the new routes.rb methods.
This works with 2.3.8, I'm not sure about 2.2.2 though.

Github like routes in Rails

Using github like chain routes in rails
I have URLs similar to this:
'localhost:3000/document_managers/[:module_name]'
'localhost:3000/document_managers/[:module_name]/1/2/3/.' # can be any level deep
Here is the route definition for them:
map.connect '/document_managers/:module',
:controller => "document_managers",
:action => :new_tree,
:module => ["A","B","C"]
map.connect '/docuemnt_managers/:module/*path',
:controller => "document_managers",
:action => "new_tree",
:module => ["A","B","C"]
Here is the problem:
The idea that module name value can't be anything except from the
given above array i.e("A","B","C") like at any time the URL must be something like
localhost:3000/document_managers/A/1 or
localhost:3000/document_managers/B/221/1 or
localhost:3000/document_managers/C/121/1
but that not the case even though
localhost:3000/document_managers/D/121/1 is treated as valid url
and module is set to D even though the "D" is not in listed array
above
I want the the URL localhost:3000/document_managers/A to
also redirect to same action i.e new_tree if the extra parameter isn't
provided as in the URL contain extra parameters
localhost:3000/document_managers/C/121/1 then the URL is redirected
appropriately to the desired controller and action but if the URL only
contain the path until the module name the Rails return a routes
ActionController::UnknownAction I don't know why as I have already
defined the controller and action.
In Rails 3.1, you can do this in your routes file to get what you want:
match '/document_managers/:module',
:controller => "document_managers",
:action => :new_tree,
:constraints => {:module => /[ABC]/}

url_for generates a url with current path inserted

I am generating a url in my controller accessed from the relative path "/hangouts/test", for a url on an external site (facebook). I want to use url_for and pass in params using hashes so it can escape them. The URL I want is this:
http://www.facebook.com/connect/prompt_permissions.php?api_key=6aca22e72866c7eaaedfb15be69c4b93&...
Using this, however:
url_for(:host => "www.facebook.com/connect/prompt_permissions.php?", :api_key => Facebooker.api_key, :next => test_hangouts_url, :cancel => root_url, :ext_perm => "publish_stream")
I instead get my current path of /hangouts/test thrown in there:
http://www.facebook.com/connect/prompt_permissions.php/hangouts/test?api_key=6aca22e72866c7eaaedfb15be69c4b93&...
As you can see, I don't want "/hangouts/test" to be in there - played a bit with the options in the API docs but stumped, anybody know how to use url_for without it inserting the current path? Thanks!
You shouldn't be using the hash form of url_for to generate links outside of your application.
Instead you should just be using the string version form:
url_for "http://www.facebook.com/connect/prompt_permissions.php?api_key=6aca22e72866c7eaaedfb15be69c4b93&next=#{test_hangouts_url}&cancel=#{root_url}&ext_perm=publish_stream"
url_for will use the current action controller/action/id unless the hash given to url_for contains one of those arguments. url_for will then generate a url from a route that matches the arguments given in the hash. The arguments to url_for used in the question generates a valid url, because it can match a route using the current controller/action. You will not be able to generate the url you want with the hash form of url for without matching a route. Providing a controller in the hash you give url_for should match the default routes that rails generates for you when you create an application, but that's not very DRY.
The better solution is to use a named route:
map.prompt_fb_permissions "/connect/prompt_permissions.php",
:host => "www.facebook.com", :controller => nil, :action => nil
then you can use the following in place of url_for whenever you want to generate this this url.
prompt_fb_permissions(:api_key => Facebooker.api_key, :next => test_hangouts_url,
:cancel => root_url, :ext_perm => "publish_stream")
You left out the controller parameter, which is why it's automatically adding your controller path ("/hangouts/test"), to your base host.
Try this:
url_for(:host => "www.facebook.com", :controller=> "/connect/prompt_permissions.php", :api_key => Facebooker.api_key, :next => test_hangouts_url, :cancel => root_url, :ext_perm => "publish_stream")

Ruby on Rails: Routing for a tree hierarchy of places

So we've got a legacy system that tracks places with IDs like "Europe/France/Paris", and I'm building a Rails facade to turn this into URLs like http:// foobar/places/Europe/France/Paris. This requirement is not negotiable, the number of possible levels in unlimited, and we can't escape the slashes.
Setting up routes.rb for http://foobar/places/Europe is trivial:
map.resources :places
...but http:// foobar/places/Europe/France complains "No action responded to Europe". I tried:
map.connect '/places/:id', :controller => 'places', :action => 'show'
...but this gives the same result, as apparently the :id ends at the first '/'. How do I make the ID cover anything and everything after the "places"?
Have a look at the Routing Guide for full documentation:
http://guides.rubyonrails.org/routing.html
Specifically section "4.9 Route Globbing".
But I think what you really want to do is declare your route like:
map.connect '/places/*id', :controller => 'places', :action => 'index'
Called with a URL like
/places/foo/bar/1
Yields a params[:id] => ["foo", "bar", "1"]
Which you could easily (re)join with "/" to yield the full string you want "foo/bar/1" (you will probably have to re-insert the leading slash manually.
That should get you going.
I tweaked Cody's answer above slightly to come up with this:
map.place '/places/*id', :controller => 'places', :action => 'show'
map.connect '/places/*id.:format', :controller => 'places', :action => 'show'
By using map.place instead of map.connect, Rails knows what resource we're dealing with and generated place_url, place_path etc helpers correctly.
Now, the 2nd line should work but doesn't thanks to the bug above, so here's a workaround for places_controller.rb that manually splits the ID and sets the format, defaulting to XML:
id, suffix = params[:id].join('/').split('.')
params[:format] = suffix ? suffix : "xml"

Resources