Do you have to mess with Rails's "routes.rb" file? - ruby-on-rails

I never touch routes.rb beyond calling map.root to set a default route. I've always been content to use URLs of the form...
/controller/action/perhaps_an_id
and it works fine.
Does this make me a bad person? Am I missing out on something totally awesome?
What if I try to adopt RESTful design? Would that mean I have to edit routes.rb or could I continue to pleasantly ignore it?
(I tried to read up on this topic in The Rails Way but it was unbearable.)

If you generate your resources with the default scaffolding then it will even include the restful routing for you in routes.rb.
If you're not using the scaffolding then the reason that it's working is because of the default routes at the bottom by default:
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
I've been following that it's best practice to remove these for production applications and instead make sure that only the resources that need to be exposed are exposed. With Rails 2.2 you can even limit the RESTful methods from map.resources by:
map.resources :posts, :only => [:index, :show]
map.resources :comments, :except => [:edit]
There's also tons of cool things you can do with nested resources, named routes, etc. They have a lot of examples in the docs (http://www.railsbrain.com/api/rails-2.2.2/doc/index.html?a=M000255&name=resources)

You may also want to make custom named routes for your marketing department (eg: mycoolsite.com/free-trial) that go off to specific controllers and actions, etc.
Ryan Bates has a series of screencasts that go over some of the neat things you can do with routes: http://railscasts.com/tags/14

Not having switched to RESTful design does not make you a bad person and if you feel no need to change keep writing your apps the 1.x way.
The majority of Rails developers has adopted REST and seems to be very happy about it. I don't think there is a need here to repeat all pro REST arguments.
You do need to add one line per resource to your routes file such as:
map.resources :posts

If you were to go RESTful, yes you would have to edit routes.rb and add your resources like,
map.resources :your_resource
or if you have nested resources,
map.resources :people do |person|
person.resources :ideas do |idea|
ideas.resources :bad_ones
end
end

Related

Rails nested resources and url helpers - how to shorten

In my routes.rb file I have the following resources:
resources :educations do
resources :semesters do
resources :module_assignments do
resources :module_exams do
resources :module_marks
end
end
end
end
Which generates this url helper:
logonname_module_assignment_module_exams_path GET /:student/module_assignments/:module_assignment_id/module_exams(.:format) module_exams#index
Is there any way to shorten this? It should redirect to the same controller and the same action. Instead of
logonname_module_assignment_module_exams_path
I would prefer something like
module_exams_path
Is there a way to solve this? I want all url-helpers like this (index, new, edit, show etc.) not just the show path.
You don't have to nest so deeply.
I personally only go as far as two deep, it just makes it easier to maintain.
But that doesn't answer the question. Or maybe it does.
With your setup. You could do something like:
match '/:student/module_assignments/:module_assignment_id/module_exams(.:format)' => 'module_exams#index', :as => :module_exams
This gives you module_exams_path as a helper.

Rails routing get and match

When I'm generating controller with methods in routes I have something like this:
get "vehicle_manufacturers/show"
Is it a good practice that after that I will write such code:
match 'vehicle_manufacturers/:id/' => 'vehicle_manufacturers#show', :as => :vehiclemanufacturers
Or, is there another way of writing this code so that will work properly?
It's best practice to follow Rails conventions for naming and routing to your actions. This lets you say:
resources :vehicle_manufacturers
This will automatically create routes for index, new, create, show, edit, update, and delete with the appropriate HTTP methods and helper names. Assuming it corresponds to a VehicleManufacturer object that conforms to ActiveModel conventions (like ActiveRecord, Mongoid, etc.), url_for will automatically Do The Right Thing™, letting you use forms and redirects and such with no extra routing-related work.
It's pretty common that you might only want a subset of these methods. That's fine too:
resources :vehicle_manufacturers, :only => [:index, :show]
You want to support additional methods outside the normal CRUD methods. Go for it:
resources :vehicle_manufacturers, :only => [:index, :show] do
get :stock_price, :on => :member
end
This would add a route named stock_price_vehicle_manufacturer mapping to /vehicle_manufacturers/:id/stock_price. Although, strictly speaking, I might consider a stock price to be a sub-resource...
The point is, try to use resources as the basis of your routing. It makes everything easier.

Creating an alias (i.e. second name) for a model in Rails

I have a production Rails 2.3.5 website, and I'd like to the change the name of a model to something that will look much better in the URLs. I know the easy way to do this is in routes.rb like this:
map.resources :announcements, :as => :posts
However, I need to support the old name as well since we're production and can't have dead links. Just using ':as' isn't going to cut it.
I'm basically looking for a way to redirect so that:
http://mysite.com/announcements/23
redirects to
http://mysite.com/posts/23
It's probably possible to do this through Apache, but I can't seem to figure out the rewrite rules. I thought maybe routes.rb would be an easier method. Not having luck there either.
Thanks!
Depends on what we mean by "redirect" - it sounds like the most efficient route might be to take your posts controller and add redirects to announcements, and let the announcements controller handle the pages. So, in PostsController:
def index
redirect_to 'announcements#index'
end
and so forth. That gives you legacy support for old links for as long as you want it, and if there ever comes a time that you don't want it anymore you can just drop the whole Posts Controller.
I ended up finding a solution that works out pretty well.
I added the :as => :posts to my routes.rb, which makes all the link helpers create links to the new URLs. Then I figured out a mod_rewrite rule to handle redirects so there aren't any broken links out there on the internets. Here's what I added to my Apache config:
RewriteEngine On
RewriteRule ^/announcements(.*) /posts$1 [R=301,L]
How about adding the route two times. With :as option and without?
//routes.rb
map.resources :announcements
map.resources :announcements, :as => :posts

Router for nested resources in a "not usual" Ruby on Rails way

I am using Ruby on Rails 3.0.7 and I am trying to set nested resource routing to make it to work in a "not regular" RoR way.
In my routes.rb file I have
resources :articles do
resources :categories, :only => [:index], :controller => 'articles/categories' # The related controller is Articles::CategoriesController
end
so that I can browse following URLs:
<my_site>/articles/1/categories
<my_site>/articles/2/categories
...
What I would to do is to access new, edit and show controller actions for categories by using the same articles/categories controller used for the nested resource stated above (that is, Articles::CategoriesController) and by accessing these URLs:
<my_site>/articles/categories/new
<my_site>/articles/categories/edit
<my_site>/articles/categories/1
<my_site>/articles/categories/2
...
How can I do that? How I must code the router?
Maybe I can do something by using the router collection method like this
resources :articles do
collection do
# match something here for the Articles::CategoriesController...
end
resources :categories, :only => [:index], :controller => 'articles/categories'
end
but I don't know how to do that.
I'm not real sure what you're trying to do with those routes, so I'm not quite sure how to answer your questions. If your intent is to be able to add a new category for a particular article, or edit all the categories for a particular article, you have to pass an ID for the article. If you're trying to create a new article and a new category all at once, you don't need category in the route, just the article and you can do something like form_for([#article,#category]) in your form and use the build method in your controller. If you can clarify, I might be able to help you further (in other words, it's not hard to construct those routes -- but it depends on what you want to do with them.

Rails 3 Routing resources scoped to a username

I have a basic understanding of rails routing, but nothing too advanced. So far I've gotten by using the RESTful resource based routes and a few custom named routes.
I am nearly done my app now though and I wanted to make some pretty urls.
In my app, each user has many pages. What's the best way to make the URL's look like www.sitename.com/username/page_name?
This will route to the pages controller's show action. Params hash includes :username and :page_name.
match "/:username/:page_name" => "pages#show"
Remember to put it last or it will match pretty much everything.
I'm not quite sure what you're using this for, but something like this might work in your routes file:
resources :users do
get 'page_name'
end
Which will produce: users/:id/page_name
You might want to check out the Railsguide on routing.
What you are looking for is a member route (section 2.9.1).
resources :users do
member do
get :cool_page
end
end
Will result in /users/:id/cool_page

Resources