Singular or plural controller and helper names in Rails - ruby-on-rails

Is there any disadvantage to using singular names for controllers and helpers? Nothing seems to rely on this. It even seems helpers don't have to make the same choice about singular vs. plural as their corresponding controllers, at least according to my limited experimentation. Is that true?

Definitely plural.
With restful routing and a singular controller
Controller:
dog_controller.rb
Routes:
map.resources :dogs # => blows up
map.resources :dog # is ok, but...
dogs_path # => blows up
dog_path # => ok
Using a plural controller
Controller:
dogs_controller.rb
Routes:
map.resources :dogs
dogs_path # => ok
dog_path # => ok
rails generate controller --help has plural examples:
Example:
`rails generate controller CreditCards open debit credit close`
CreditCards controller with URLs like /credit_cards/debit.
Controller: app/controllers/credit_cards_controller.rb
Test: test/controllers/credit_cards_controller_test.rb
Views: app/views/credit_cards/debit.html.erb [...]
Helper: app/helpers/credit_cards_helper.rb

Using plural names for controllers is just a convention.
Plural names usually sound more natural (especially for controllers that are tied directly to a specific model: User -> Users, etc.), but you can use whatever you want.
As for helpers, all helpers are available for all controllers by default, so technically, how you name your helpers doesn't matter at all. It's just another convention to keep a controller's helper functions in a helper with the same name as the controller.

A Model is singular because it references a single object like User. A controller is plural because it is the controls (methods) for the collection of Users. How one names the routes is all up to that individual developer. I've never had a user complain that a URL for a web request is singular or plural. The end result to maintain a common convention for current and future contributors while serving quality page displays or the API requests for the end users.

You have a very complete explanation in the Rails guides:
http://edgeguides.rubyonrails.org/routing.html#resource-routing-the-rails-default

It is the Rails convention that one controller handles one model, whether one or more instances of that model can exist during runtime. However, you can have a Rails application where (some of) the controllers (and the associated views) are not associated with any particular model, but rather handle a more complex set of functionality. In this case, the automatic pluralization doesn't make any sense.
The Rails application I'm currently working on fits into this category, and it's simply an irritation to me that Rails expects that the identifiers I define as a singular in one place are then used in their plural forms in other places. For example, I might want to define something like this in config/routes.rb:
resource :dashboard, :only => [:show]
and then I want a controller DashboardController to display summary information about certain aspects of the application, gathering information from more than one database table. So here, Dashboard does not refer to any model of the application, and it would be just weird to have the controller's name be DashboardsController.
I found a good solution to the irritation of automatic pluralization in this answer. In short, edit file config/initializers/inflections.rb and add the words you don't want to be automatically pluralized to this definition:
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable %w( dashboard foo bar baz )
end

If the controller is a resource then it must be plural...
For example
Controller
articles_controller.rb
Model
article.rb
But you can use singular controller names when you do not have corresponding models like
welcome_controller.rb

The naming convention of controllers in Rails favors pluralization of the last word in the controller's name, although it is not strictly required (e.g. ApplicationController).
For example, ClientsController is preferable to ClientController, SiteAdminsController is preferable to SiteAdminController or SitesAdminsController, and so on.
Following this convention will allow you to use the default route generators (e.g. resources, etc) without needing to qualify each :path or :controller, and will keep URL and path helpers' usage consistent throughout your application.
Ref: Controller Naming Convention-Rails Doc

I feel better when I use singular for Controller name

Using plurals just sounds better, and then if you have a controller that handles a singular resourse, ie user, then you can still name the url /user.
With helpers there is often no need to have a helper for every controller, and often there will be helper methods you can use ascorss multiple controllers and rather litter them all through your application helper you could put them in custom helpers instead like eg layout_helper or any other well named file.

Related

What is a good naming convention for Rails custom controller actions regarding formulation (noun vs verb)?

When defining new actions in controllers I often find myself asking how should I formulate the name of the action correctly. Rails default CRUD actions all seem to follow the pattern of verb (new, create, edit, update, destroy, index) but is it a bad habit to use a noun? For ex. payment_history?
I found a lot of information describing the naming conventions for different files and classes and regarding the proper syntax but none about controller#actions from formulation part.
EDIT: I am asking about custom-defined actions not renaming the Rails default CRUD actions.
In my opinion, important thing about choosing name of the action should not be based on whether it is a noun or a verb, the name of the action should describe the behavior of the action itself, whether it calculates/gets/loads/renders/etc something. So that, when another person (or you after a long time) reads the code, he/she should be able to easily understand what is this action used for and what is expected result from this action.
Otherwise you could just name it is as * whatever * since ruby doesn't prohibit you to do so.
As example we can take a look at payment_history and list_payment_history. If I am reading the code and see action named list_payment_history, I understand that it lists the history, even without looking at the code I understand the purpose of the action. However if I see payment_history, I can only understand that it has something to do with history, not the exact meaning, does it show history, or may be sort history, archive history... no concrete understanding towards the purpose of the action.
Assuming you're following the conventional RESTful methodology, it is going to be easiest to follow the convention of index, show, new/create, edit/update and destroy. That is, unless you have a well-grounded reason not to, but then you ought to be able to justify to yourself and possible other developers why the default action names are not sufficient.
Using the default method names, you get a lot of the routing etc. stuff "for free", as Rails assumes you're following the convention. Also, do note that things that might not immediately sound like "resources" can often easily be modeled as such, e.g. your example "payment_history" may well be a subresource of another resource (a User?), in which case you'd have a singular nested route such as GET /users/{user_id}/payment_history. This route would then call PaymentHistoryController#show, as demonstrated in the Rails guide section on singular resources.
I don't know that it matters so much, though in general I think you're looking for a verb. Your models are typically nouns, and controllers define actions.
Controllers In rails acoording to my reading and experience
Controller class names use CamelCase and have Controller as a suffix. The Controller suffix is always singular. The name of the resource is usually plural.
Controller actions use snake_case and usually match the standard route names Rails defines (index, show, new, create, edit, update, delete).
Controller files go in app/controllers/#{resource_name}_controller.rb.
Example:
# app/controllers/bigfoot_sightings_controller.rb
BigfootSightingsController < ApplicationController
def index
# ...
end
def show
# ...
end
# etc
end
# app/controllers/profiles_controller.rb
ProfilesController < ApplicationController
def show
# ...
end
# etc
end

Should About page be named Abouts?

Ruby on Rails naming convention says controllers should be plural, as should associated views. Models are singular.
That makes sense if you have a controller name orders. It is most likely going to have a model named order. However, should the about page be named abouts? That seems odd.
The about page isn't going to have any associated model. Does that make a difference with singular vs plural naming conventions?
For static content pages (eg. 'about us', 'terms and conditions', 'privacy policy', etc.) I typically stray away from typical REST conventions.
I would create a single PagesController and have one action for each page (eg. def about_us; end. Each action would just render the view with the content for that page.
By following the Rails convention of naming, you can standardize a lot of things in your project but there can be exceptions.
You can use about instead of abouts if you want, then name the file as about_controller.rb and inside the file, have the class name as: class AboutController. You have to match the class and the file name, then it will work just fine. Rails won't complaint about this.
But again, it depends on the use case. In this use case, I don't think you really need a controller for about page :-) You should be able to handle that in any other multi-purpose/common controller.
You can use rails pluralize method to generate plurals. Use rails console for this.
"about".pluralize

Rails named route with dynamic segments URL generation from model

Ruby on Rails 4.2+ only, please!
I've been looking all over for tips on how to make URLs pretty in Rails, and I'm struggling to see a solution I like.
What I want:
Hypothetical example: given Topic, Course, etc. models that have a bunch of fields (including URL-friendly slugs), I want to be able to
# ../routes.rb
# Match urls of the form /edu/material-engineering. These are read-only
# public URLs, not resources.
get 'edu/:slug', to: 'education#topic', as: :learn_topic
get 'edu/course/:id/slug', to: 'education#course', as: :learn_course
...
# I also have admin-only resource-oriented controllers for managing
# the content, but that's separate.
namespace :admin do
resource :topic
resource :course
...
end
# ../some_view.html.erb
# Generate URLS like this:
<%= link_to topic.name, learn_topic_path(topic) %>
<%= link_to course.name, learn_course_path(course) %>
What I don't want:
Messing with to_param. That's a dirty hack and completely breaks separation of concerns.
Resource/RESTful routing. There are no CRUD operations here other than "read."
link_to 'text', course_path(id: course.id, slug: course.slug). This completely defeats the purpose of not requiring views to know what params are required to generate a URL for a course.
EDIT: I know FriendlyId exists, but I'm precisely trying to understand how this sort of thing can be done and what the mechanics are, so that's not a solution for now.
There has to be a way to tell the named route helper topic_path(topic) to take the required parameters in the route (e.g, :slug, :id, whatever else) from the topic model object.
Anybody know? Thanks!
The best I've been able to come up with: just override the *_path helpers with my own implementation.
If you know a way to make the default helpers work, please chime in!
This problem boils down to one issue: the auto-generated *_path and *_url helpers don't give me the flexibility I want. What I want them to do is trivial, so without another option, I can just write my own:
module ApplicationHelper
def learn_topic_path(topic)
"/edu/#{topic.slug}"
end
...
end
Writing a few _path/_url helper overrides avoids all kinds of complication, and allows you to keep out of to_param, avoid including new plugins, etc.
One could probably go another step forward and generate the static components of the route from known routing rules, as well as infer what attributes one needed to extract from a model if the dynamic segment names line up to the model attribute names, but that starts to break down once you do more complicated things or add multiple models (e.g., 'edu/:topic_slug/:course_slug').
The big downside to doing this is that you now have to update routes in two places every time you change them: the route definition itself in routes.rb as well as the corresponding route helper in application_helper.rb. I can live with that for now.
You can use FriendlyId gem to achieve that.
Here's the link:
https://github.com/norman/friendly_id/blob/master/README.md
Let me know if you have questions.

Rails router: Avoiding long helpers

Consider the following snippet from router.rb
resource :user do
namespace :settings do
resource :access_filter
end
get 'settings'
end
This generates the URL's I want (user/settings/access_filter), but it produces an undesired directory structure and some long url helpers.
In this case, the helper becomes new_user_settings_access_filter and I would prefer just to have new_access_filter. And Rails expects the AccessFiltersController to reside in a module named Settings.
I would like a way to keep a flat directory structure, a flat url helper structure, but a "nested" URL structure. As long as no parameters are neccessary, I don't think my controllers and views needs to know that access filters are nested under the user model and I would like to retain the opportunity to move them to say options/access_filter without breaking the site.
Sugggestions on how to get there would be appreciated.
If you only want to prefix the path, you could avoid the nesting and any hassle involved by using a separate scope. Organizationally, this seems to make sense as well, since you effectively want to decouple the access filter routes from user.
scope "user/settings" do
resource :access_filter
end
# then if you wanted to change it later, it's simply
scope "options" do
resource :access_filter
end
scope is a lower level function actually used by namespace. It's far more flexible, and allows you to decorate paths without changing the controller lookup and route names, among other things.

What is the logic behind Rails' default restful resource code?

I'm Learning Rails. Lots of the conventions make great sense. The convention for code that maps to controller actions is odd:
//code url controller action
tweets_path /tweets/ def index
tweet /tweet/ID def show
new_tweet_path /tweets/new def new
edit_tweet_path(tweet) /tweets/ID/edit def edit
Why aren't the automatically generated method helpers done in the same symmetrical way as the controller actions? eg:
//code
tweet_index
tweet_show(tweet)
tweet_new
tweet_edit(tweet)
I'm so new I'm sure there's a perfectly good reason, I just don't know it yet :)
There are two asymmetries here.
The first is plural vs. singular route helpers. Why are some helpers tweets_* helpers while others are tweet_* helpers?
The answer is that some resource routes are member routes and others are collection routes. Member routes have to do with an instance of a resource and collection routes have to do with all instances of a resource as a group (unless the resource is singular in which case there are no collection routes). The index action is a collection route and the show action is a member route.
You can declare your own member and collection routes like this:
# routes.rb
resources :tweets do
member do
get :duplicate
end
collection do
get :summarize
end
end
This will create two helpers in addition to the standard ones. Note that Rails will create route helpers that are appropriately singular or plural.
a summarize_tweets_path helper that does not take a parameter
a duplicate_tweet_path helper that does
Official docs are here.
The second asymmetry is that the action is left out of the helper for many of the built-in resource actions. I suppose this could have been for brevity, but I don't really know.
Edit
After thinking about it, the action name was dropped because there is path overloading in Rails and REST. The '/tweet/:id' path could be the show, update, or delete action depending on the HTTP verb. Basically, the path tells you what you are operating on but not what action to take.
The helper methods are generated in a way that makes them more readable by making them more like parts of sentences. Saying 'Create a link to a new tweet' sounds better than 'Create a link to a tweet new'. It helps to keep this in mind as well when naming any custom actions, using names that fit sentences makes it easier to comprehend and remember since this is how we learn to speak.
One reason for it not being symmetrical is that the mappings depends on the HTTP action. For example, a GET to /tweets map to the index action, but a POST to /tweets maps to the create action.

Resources