Having a dot in the id of rails routes - ruby-on-rails

I am working on Rails 2.3.11. If I have a url like http://www.abc.com/users/e.f.json , I expect the id to be 'e.f' and the expected format to be 'json'. Can someone please suggest a way to do it.
Thank you!

Because of the :format convention, Rails will parse all parameters without any dots. You can have route parameters with dots if you want:
# You can change the regex to more restrictive patterns
map.connect 'users/:id', :controller => 'users', :action => 'show', :id => /.*/
But since both '*' and '+' regex wildcards are greedy, it will ignore the (.:format) param completely.
Now, if you absolutely need to have dots in the username, there is a pseudo-workaround that could help you:
map.connect 'users/:id:format', :controller => 'users', :action => 'show', :requirements => { :format => /\.[^.]+/, :id => /.*/ }
map.connect 'users/:id', :controller => 'users', :action => 'show'
The downside is that you have to include the dot in the :format regex, otherwise it would be caught by the username expression. Then you have to handle the dotted format (e.g.: .json) in your controller.

Here is a solution similar to andersonvom's, but keeps it all in one rule (and uses some modern Rails routing abbreviations).
map.connect 'users/:id(.:format)', to: 'users#show', id: /.*?/, format: /[^.]+/
(Note the . in front of :format)
The trick is to add an optional format, (.:format) and make the id regex non-greedy so the format is recognised. Keeping it in one rule is important if you want to give the route a name, so that you can use it for redirects, links, etc in a format-agnostic way.

Related

Rails route: pull entire path string into one parameter

I've just added a CMS to my rails 2.2.2 app. I want to have it set up so that at the bottom of my routes i have a catch-all which shoves the entire path into a single parameter and then calls the cms controller, which then looks for a page matching that path
eg
http://mysite.com/something/about/foo
=> {:controller => "cms", :action => "show", :page => "something/about/foo"}
I can't figure out what options i need to add (if any) to stop it splitting on the slashes. Any ideas anyone? Remember this is rails 2. Thanks!
Just discovered the answer to this in the official rails api documentation (doh):
4.9 Route Globbing
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',
In my case:
map.connect "/*page", :controller => "cms", :action => "show"
means that
http://mysite.com/something/about/foo
=> {:controller => "cms", :action => "show", :page => ["something", "about", "foo"]}
which is fine as i can easily then join params[:page] to get the full path again.
thanks for reading :)

Rails URL question

If I have a Users model, and then an individual user, say, person1, is there a way to have the url: www.myapp.com/person1 show what www.myapp.com/users/person1 would? What would that be called?
Thank you!
You should define a route in your routes.rb file:
match "/:user" => "users#show"
and you'll get the username given in params[:user]. But you need to know that this kind of route could override other routes defined, because it will match any string, so you should at least define some constraints on the username.
For example if your usernames matches a regexp you could define it as a constraint
match "/:user" => "users#show", :constraints => { :user => /some-regexp/ }
and don't forget to set this route as the last one in your routes file, otherwise it will clash for sure with other routes.
Read this for full reference
add "two" routes for the same thing to your app.
# Shorter url to show store items by tags
map.connect '/s/tags',
:controller => 'music',
:action => 'show_by_tags'
map.connect '/music/s/tags',
:controller => 'music',
:action => 'show_by_tags'

How do I specify a default in a rails 2.3 route?

In my Rails 2.3.11 app, I want to specify that the default format for a route is :xml. According to the documentation I can do this using :defaults
map.connect '/myroute', :controller => 'mycontroller',
:action => 'myaction',
:defaults => {:format => :xml}
The documentation specifically says this should work:
You can also define other defaults in a route by supplying a hash for
the :defaults option. This even applies to parameters that are not
explicitly defined elsewhere in the route.
But if I do that, then I get this error:
/Users/simon/myproject/vendor/rails/actionpack/lib/action_controller/routing/builder.rb:107:in `assign_route_options':
format: No matching segment exists; cannot assign default (ArgumentError)
I see that a lighthouse ticket has been raised about this; a respondent notes that it works for resources but not named routes; an admin has incorrectly marked it as fixed because he's tested it on resources. Ho hum.
Elsewhere it is suggested that i do it like this:
map.connect '/myroute', :controller => 'mycontroller',
:action => 'myaction',
:format => :xml
but then if I test it
assert_generates '/myroute', :controller => 'mycontroller',
:action => 'myaction'
I get told that no route matches :controller => 'mycontroller', :action => 'myaction' - I have to put the format in by hand, so it isn't a default.
How do I specify a default in a rails 2.3 route? Do I need to get them to reopen the ticket and actually fix the bug? Is there any hope that that will happen now Rails 3 is out?
Hmmm that is pretty weird. I've used :defaults hash in a named route, and it worked for me. Can you try using a named route instead and see if it works ?
map.myroute '/myroute', :controller => 'mycontroller',
:action => 'myaction',
:defaults => {:format => :xml}

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.

Rails routes matching query parameters

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?

Resources