Before all, this question is about Rails 2.x.
I live in a spanish language country and the URLs for my web apps should be in spanish. I always created spanish spelled actions for my controllers until now, but that just turn off many of the advantages for using REST, like the built-in PUT method => edit action stuff.
So, I wanna know how to modify the routes.rb file for redirect all the traffic for all my existing and future resources without losing the RESTful standars.
Is this possible?
Example:
POST /inmuebles
:controller => inmuebles, :action => create
GET /inmuebles
:controller => inmuebles, :action => index
GET /inmuebles/nuevo
:controller => inmuebles, :action => new
Piggy backing off of Andrew V's answer, but couldn't preview my comment...
Since all of your resources will likely have the same actions that need the same path names, you can use a with_options block to set these for all routes.
For example:
map.with_options :path_names => {:new => 'nuevo', :edit => 'editar'} do |rt|
rt.resources :ineubles
rt.resources :pollos
rt.resources :gatos
end
Use the :path_names option:
map.resources :inmeubles, :path_names => { :new => 'nuevo'}
You can also try this i18n_routing gem http://github.com/kwi/i18n_routing
Related
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.
I have a rails model called 'audioclip'. I orginally created a scaffold with a 'new' action, which I replaced with 'new_record' and 'new_upload', becasue there are two ways to attach audio to this model.
Going to /audioclips/new_record doesn't work because it takes 'new_record' as if it was an id. Instead of changing this, I was trying to just create '/record_clip' and '/upload_clip' paths.
So in my routes.db I have:
map.record_clip '/record_clip', :controller => 'audioclips', :action => 'new_record'
map.upload_clip '/upload_clip', :controller => 'audioclips', :action => 'new_upload'
When I navigate to /record_clip, I get
ActionController::MethodNotAllowed
Only get, head, post, put, and delete requests are allowed.
I'm not extremely familiar with the inner-workings of routing yet. What is the problem here? (If it helps, I have these two statements above map.resources => :audioclips
Yes, your two routes are conflicting with your mapped resource (the map.resources => :audioclips bit).
If you want to continue using resources, I suggest you change that line to:
map.resources => :audioclips,
:new => {
:new_record_clip => :post,
:new_upload_clip => :post }
If you want some more information, the Rails guide is incredibly helpful on this topic:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
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 my current rails application I have a bunch of named routes defined to deal with the static content like this:
map.with_options :controller => 'static_content' do |static|
static.imprint 'imprint', :action => 'imprint'
static.menu1 'menu1', :action => 'menu1'
static.menu1_sub1 'menu1/sub1', :action => 'menu1_sub1'
static.menu1_sub2 'menu1/sub2', :action => 'menu1_sub2'
static.menu2 'menu2', :action => 'menu2'
...
end
Now I'd like to refactor this quite disgusting piece of routing to have something like this:
map.connect 'menu1/:action', :controller => 'static/menu1'
map.connect 'menu2/:action', :controller => 'static/menu2'
...
I created the controller namespace static and map the actions of all those controllers in the namespace. But now - of course - all those helpful route helpers like menu1_sub2_path stop working and I'll have to change them.
Uff! Refactor all usages of path helpers to ugly :controller-:action-style?
So my question is if anybody sees a good way to surround this. Is there a way to define those path helpers - or the way they are created? Or even a smarter way to do those nasty mappings?
Thanks for your help,
Joe
map.with_options :controller => 'static_content' do |static|
static.page ':action'
end
then call it:
page_path(:imprint)
Right now my user profile URLs are like so:
http://example.com/users/joeschmoe
And that points to the show method in the user controller.
What I'd ideally like to do is offer user profile URLs like this:
http://example.com/joeschmoe
So, what sort of route and controller magic needs to happen to pull that off?
I disagree with what jcm says about this. It's not a terrible idea at all and is used in production by the two biggest social networks Facebook and MySpace.
The route to match http://example.com/username would look like this:
map.connect ':username', :controller => 'users', :action => 'show'
If you want to go the subdomain route and map profiles to a URL like http://username.example.com/, I recommend using the SubdomainFu plugin and the resulting route would look like:
map.root :controller => 'users', :action => 'show' , :conditions => {:subdomain => /.+/}
These broad, catch all routes should be defined last in routes.rb, so that they are of lowest priority, and more specific routes will match first.
I also recommend using a validation in your User model to eliminate the possibility of a user choosing a username that will collide with current and future routes:
class User < ActiveRecord::Base
validates_exclusion_of :username, :in => %w( messages posts blog forum admin profile )
…
end
This does not make sense unless you have no controllers. What happens when you want to name a controller the same as an existing user? What if a user creates a username the same as one of your controllers? This looks like a terrible idea. If you think the /user/ is too long try making a new custom route for /u/
So your custom route would be...
map.connect 'u/:id', :controller => 'my/usercontroller', :action => 'someaction'
In routes.rb this should do the trick:
map.connect ":login", :controller => 'users', :action => 'show'
Where login is the name of the variable passed to the show method. Be sure to put it after all other controller mappings.
Well, one thing you need is to ensure that you don't have name collisions with your users and controllers.
Once you do that you, can add a route like this:
map.connect ':username', :controller => 'users', :action => 'show'
Another thing people have done is to use subdomains and rewrite rules in the web server, so you can have http://joeshmoe.example.com
In Rails 4 to skip controller from url you have to do add path: ''.
resources :users, path: '' do
end