Github like routes in Rails - ruby-on-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]/}

Related

Rails url_for from string with parameters

I've got a site-local tinyurl I'm trying to make, so I need to show the full path of a URL that doesn't correspond to a controller action, and this doesn't work:
url_for("tiny/#{identifier}", :only_path => false)
because the url_for that takes a string doesn't then take any parameters.
How can I accomplish this?
Edit as per comment:
config/routes.rb:
get 'tiny/:id' => "original_controller#show", :constraints => {:id => /\d+/}
get 'tiny/:name' => "original_controller#by_name"
rake:
GET /tiny/:id(.:format) original_controller#show {:id=>/\d+/}
GET /tiny/:name(.:format) original_controller#by_name

Escaping elements in a URI 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.

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.

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