Rails routes matching query parameters - ruby-on-rails

Rails routes are great for matching RESTful style '/' separated bits of a URL, but can I match query parameters in a map.connect config. I want different controllers/actions to be invoked depending on the presence of a parameter after the '?'.
I was trying something like this...
map.connect "api/my/path?apple=:applecode", :controller => 'apples_controller', :action => 'my_action'
map.connect "api/my/path?banana=:bananacode", :controller => 'bananas_controller', :action => 'my_action'
For routing purposes I don't care about the value of the parameter, as long as it is available to the controller in the params hash

The following solution is based on the "Advanced Constraints" section of the "Rails Routing from the Outside In" rails guide (http://guides.rubyonrails.org/routing.html).
In your config/routes.rb file, include a recognizer class have a matches? method, e.g.:
class FruitRecognizer
def initialize(fruit_type)
#fruit_type = fruit_type.to_sym
end
def matches?(request)
request.params.has_key?(#fruit_type)
end
end
Then use objects from the class as routing constraints, as in:
map.connect "api/my/path", :contraints => FruitRecognizer.new(:apple), :controller => 'apples_controller', :action => 'my_action'

Unless there is a concrete reason why you can't change this, why not just make it restful?
map.connect "api/my/path/bananas/:id, :controller => "bananas_controller", :action => "my_action"
If you have many parameters, why not use a POST or a PUT so that your parameters don't need to be exposed by the url?

Related

Rails routes with clean urls

My problem is i want to remove the querystring part of this URL and make it clean.
http://staging.mysite.com/mycontroller?name=/philippines/about-manila
currently i have MyController.index() and I parse the name parameter in this method.
What i would eventually want is this :
http://staging.mysite.com/mycontroller/philippines/about-manila
the parameter part 'philippines/about-manila' can have arbitrary number of parameters, like
http://staging.mysite.com/mycontroller/philippines/about-manila/people
How can i do this in routes?
It sounds like you want route globbing. If you use:
map.my_route '/mycontroller/*parts',
:controller => :mycontroller,
:action => :index
and then go to the URL http://staging.mysite.com/mycontroller/philippines/about-manila/people, then your mycontroller controller's index action will be called, and params[:parts] will contain the array ["philippines", "about-manila", "people"].
Is it really arbitrary — or just variable?
If it's just variable, you can enclose optional parameters in parentheses:
match '/:city(/:section(/:subsection))', :controller => :mycontroller,
:action => :index
For Rails 2.x:
map.connect '/:city(/:section(/:subsection))', :controller => :mycontroller,
:action => :index
For Rails 2.x you can use
map.my_route '/:my_param', :controller => :mycontroller, :action => :index
Then in your controller you can access
params[:my_param]
If you want links just go with
my_route_path(:my_param => "mytekst")

How to pass a default query param with Rails 2.3.x routing

I'm trying to do something trivial. I have a bunch of URLs that I need to map like the following:
http://example.com/foo
http://example.com/foo/something
Both need to go to the same controller/action. The problem I'm having is when http://example.com/foo is invoked, I need to specify a default query parameter. I thought that's what the :defaults hash does in routes.rb, but unfortunately the following doesn't work:
map.connect 'foo', :controller => 'something', :action => 'anaction',
:defaults => { :myparam => 'foobar' }
This should route http://example.com/foo to the something controller, anaction action, and make params[:myparam] point to the string "foobar".
I'm assuming for the second example http://example.com/foo/something, I'll need an additional route.
What's the best way to tackle this?
I wouldn't complicate things by adding such logic to my routes file, I'd just do it in my action:
params[:my_param] ||= 'foobar'
Untested, but:
map.connect 'foo', :controller => 'something', :action => 'anaction', :myparam => 'foobar'
It looks like the :controller and :action arguments in there are not in any way special, but just end up feeding into params. The 2.3.8 documentation seems to confirm this.
More formally, you can include
arbitrary parameters in the route,
thus:
map.connect ':controller/:action/:id', :action => 'show', :page => 'Dashboard'
This will
pass the :page parameter to all
incoming requests that match this
route.

Get SEO friendly URLS with Rails without method_missing?

Currently we are using method_missing to catch for calls to SEO friendly actions in our controllers rather than creating actions for every conceivable value for a variable. What we want are URLS like this:
/students/BobSmith
and NOT /students/show/342
IS there a cleaner solution than method_missing?
Thank you!
You can define a route for that particular format fairly easily.
map.connect "/students/:name", :controller => :students, :action => :show, :requirements => {:name => /[A-Z][A-Z]+/}
Then in your show action you can find by name using params[:name].
You can create a catch-all route. Put this at the bottom of config/routes.rb with whatever controller and action you want:
map.connect '*path', :controller => '...', :action => '...'
The segments of the route will be available to your controller in the params[:path] array.

Can controller names in RESTful routes be optional?

With a standard map.resource routing mechanics and several nested resources the resultant routes are unnecessarily long. Consider the following route:
site.org/users/pavelshved/blogs/blogging-horror/posts/12345
It's easy to create in routes.rb, and I'm sure it follows some kind of beneficial routing logic. But it's way too long and also seems like it's not intended to be human-readable.
A nice improvement would be to drop controller names, so it looks like:
site.org/pavelshved/blogging-horror/12345
Clear, simple, short. It may become ambiguous, but in my case I'm not going to name any user "users", for instance.
I tried setting :as => '', but it yields routes like this: site.org//pavelshved//blogging-horror//12345 when generating them by standard helpers.
Is there a way to map resources in such a way, that controller names become optional?
You're looking for the :path_prefix option for resources.
map.resources :users do |user|
user.resources :blogs do |blog|
blog.resources :posts, :path_prefix => '/:user_login/:blog_title/:id'
end
end
Will produce restful routes for all blogs of this form: site.org/pavelshved/bogging-horror/posts/1234. You'll need to go to a little extra effort to use the url helpers but nothing a wrapper of your own couldn't quickly fix.
The only way to get rid of the posts part of the url is with named routes, but those require some duplication to make restful. And you'll run into the same problems when trying to use route helpers.
The simplest way to get what you want would be to create a route in addition to your RESTful routes that acts as a shorthand:
map.short_blog ':user_id/:blog_id/:id', :controller => 'posts', :action => 'show'
You'll have to change the URL bits to work with how you're filtering the name of the user and the name of their blog. But then when you want to use the shorter URL you can use all the short_blog_* magic.
Straight out of the default routes.rb:
map.connect 'products/:id', :controller => 'catalog', :action => 'view'
You could write:
map.connect ':user_id/:blog_id/:id', :controller => 'posts', :action => 'show'
But be sure to include that in the very end of the file, or it will try to match every three levels deep url to it.
Try this
map.pavelshved '/pavelshved/', :controller => :users, :action => view or
map.pavelshved '/:id', :controller => :users, :action => show do | blogs|
blogs.bloging '/:id', :controller => :blogs, :action => show do | post|
post.posting '/:id', :controller => :posts, :action => show
end
end
I hope it work :)
Google "rails shallow routes" for information about this.

? in routes.rb with map.with_options ruby

I'm using named routes in my ruby code. I come from the phpworld where you'll pass information using $_GET and $_POST. I was wondering if there's a way to put this into the routes.rb like this:
map.with_options :controller => 'test' do |m|
m.someurl 'someurl?search=someterm', :action => 'index'
end
Currently it's returning can't convert Hash into String. Thanks!
Justin
If you want to just use a Query String, you don't need to tell your route at all. The params object will contain any passed parameters.
map.with_options :controller => 'test' do |m|
m.some_url 'someurl', :action => 'index'
end
Then when you use the helper method:
some_url_path(:search=> "someterm")
Will create the query string value for you.
However, if you want to pass a parameter to a controller, you can bind them in your route:
map.connect ':controller/:action/:id/:search'
In your controller you can then access:
params[:search]
In your case this would up being something like:
map.with_options :controller => 'test' do |m|
m.some_url 'someurl' :action => 'index'
end
The Rails Routing Guide provides an excellent overview on the subject.

Resources