Singular-named routes in Ruby on Rails - ruby-on-rails

I have a fair amount of singleton routes in a Ruby on Rails app, for example:
resource :sessions, :only => [:new, :create, :destroy]
resource :avatars, :only => [:edit, :update]
but the resources themselves are named using the plural form (avatars instead of avatar). I remember reading that this is the way I should do it (somewhere in Rails' documentation) but it always bothered me: I'd rather type edit_avatar_path rather than edit_avatarS_path. Not that it looks ugly (it does), but I tend to forget the plural and get errors.
Now I'm reading the book The Rails 3 Way and in there it explains singular or singleton resources and just shows this code:
resource :profile
and shows the methods profile_path and edit_profile_path without giving any further explanation whether using the singular name would cause any trouble or not.
Can anybody enlighten me in whether there's any potential issues by using the singular name? Any advantages to using the plural?

I'm fairly certain using the singular name for singular resources is correct. The Rails Routing Guides appears to confirm this, as does the Rails API documentation for resource.

Related

What's the "Rails way" to route a "diff" between two instances of the same model?

I'm building a "Brand personality" tool that gives you a report based on the text you share on social media.
I have a model PersonalityReport and in routes I have resources :personality_reports.
A new feature is to offer a "diff" between two reports and I'm trying to work out the most "guessable" way to model this in routes.
Ideally I'd like GET /personality_reports/:personality_report_id/diff/:id or something along those lines, and while I could simply put that into routes as a GET route, is there a more Railsy way of specifying a route using the resources / collections style so that my routes.rb file is more easy to understand?
The 'neatest' way can think of is:
resources :personality_reports, param: 'personality_report' do
member do
get 'diff/:id', to: 'personality_reports#action', as: 'diff_route'
end
end
Where obviously to: is your controller#action, and as: is the name of your route. After running rake routes you will see this generates:
diff_route_personality_report GET /personality_reports/:personality_report_id/diff/:id(.:format) personality_reports#action
I think whatever you mentioned is good enough,
resources : personality_reports do
resources :diffs, only: [:show]
end
So, routes like below,
personality_report_diff GET /personality_reports/:personality_report_id/diffs/:id(.:format) diffs#show
NOTE: You can also make diff route in singular resource :diff if you want to make it as singular resource.

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.

Rails Remove Certain routes

I have a rails app and I have some custom routes. I have a database called Reports. In my routes.rb i have match '/new' => 'reports#new' however the problem is that /new goes to the right place, but /reports/new is also still active. Is there a way to "deactivate" the standard /reports/new so that only /new works?
If you're only interested in disabling one action except may be more appropriate than only. It works in a similar way.
... :except => :new
http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
Sure, there is. You can use the only option as in (for example):
resources :reports, :only => [:create, :edit, :update]
which defines routes only for the specified actions (run rake routes to see all the routes)
(so it doesn't remove routes, it just does not generate them)
Edit: Plus, of course, there's also the except option (also see #Andy Gaskell's anwers) - which generates all routes except for the given actions, see the docs.

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.

Do you have to mess with Rails's "routes.rb" file?

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

Resources