I was building a Rails application today with a noun that has interesting pluralization rules: fish. Fish is both singular and plural, which causes a little complexity for the “convention over configuration” strategy of Ruby. In the past I’ve worked around this by using nouns that don’t have this characteristic, but wanted to figure this out this time.
The issue is that for a noun like “bird”, the convention is that we list all the birds in the database by going to a url like http://app/birds, and a specific bird by selecting its ID in the URL like so: http://app/bird/27. That’s the convention in the routing logic. The challenge then, for “uncountable nouns” like fish, is that the routing logic thinks that http://app/fish is an error, because it’s singular and needs a trailing /ID.
I stumbled over this posting, which is excellent and helped me understand more about what Rails is doing under the hood. So after I removed all my hacky workarounds that didn’t work (include forcing a “Fishes” controller) I noticed that “rake routes” has some lines of interest (reduced for brevity):
birds GET /birds(.:format) birds#index bird GET /birds/:id(.:format) birds#show fish_index GET /fish(.:format) fish#index fish GET /fish/:id(.:format) fish#show
Note that we have birds and bird for paths, and we have fish_index and fish! My ultimate problem was that fish_path wasn’t working in a link_to:
<%= link_to 'Fish List', fish_path, class: "btn btn-large btn-primary" %>
that is to say, it rendered the link in the containing page, but when clicked, gave an error because of the missing ID. The solution is obvious now: replace with fish_index_path:
<%= link_to 'Fish List', fish_index_path, class: "btn btn-large btn-primary" %>
By the way, the work is for a non profit that I’m helping out dealing with water pollution. I’ll update more later when there is something concrete to talk about.