Fighting Rails RESTful Routes Conventions

Rails Fans,

Back in the 2.x days I converted my personal site to Rails. I
eventually got tired of fighting Rails conventions and tried other
options. I’m now back and giving Rails another look. I’ve been
tinkering with another personal site and have it partially implemented
in both Rails 3 and Django. I’m sure some of my preferences will make
most Rails developers cringe. I tend to try to CamelCase everything.
Also, Rails RESTful routes don’t quite make sense to me. Logic would
dictate that collection routes should be plural and member routes
should be singular, instead of them both being plural. Using recipes
as an example, my personal preference would be for:

/Recipes

to be the index with a list of recipes. For viewing a single recipe,
using a slug, it would make more sense for the route to be something
like:

Recipe/Beef-Brisket

instead of:

Recipes/Beef-Brisket

Is there a way to configure RESTful routes to use plural collection
routes and singular member routes? For the moment I have all of my
routes mapped separately via match statements but I’d like to find an
easier way, especially if/when I get to a point where nested resources
would come in handy.

Kevin
http://www.RawFedDogs.net
http://www.WacoAgilityGroup.org
Bruceville, TX

What’s the definition of a legacy system? One that works!
Errare humanum est, ignoscere caninum.

I don’t think you’ll find much information about that. REST is one of
the
core principles of Rails.

It can probably be done by hacking parts of
ActionDispatch/Routing/Mapper,
or by writing a gem to do so.

I also think the default routes make a lot of sense…

The way I see it - if you were to create a folder on your computer to
store
recipies, what would you call it? Recipe or recipes? I’d call it recipes
since it holds more than one recipe. Then under there, you’d have each
of
your recipes as a file/folder. RESTful routes are designed to emulate
that.

And is the case sensitivity that big of a deal? You could probably also
do
this by hacking ActionDispatch.

Might want to start your search by looking at the Resouces module in
action_dispatch\routing\mapper.rb

On Wed, Apr 27, 2011 at 12:36:06PM -0700, Tim S. wrote:

The way I see it - if you were to create a folder on your computer
to store recipies, what would you call it? Recipe or recipes?

I’d create a directory, and call it Recipes.

I’d call it recipes since it holds more than one recipe. Then under
there, you’d have each of your recipes as a file/folder. RESTful
routes are designed to emulate that.

If that’s how I was storing my recipes, that would make some sense.
But, I’m storing them in a database, so I have a little more
flexibility in how they’re presented. If you were talking about a
beef brisket recipe, would you call it a beef brisket recipe, or a
beef brisket recipes? In that context, which of:

/Recipes/Beef-Brisket

/Recipe/Beef-Brisket

seems more natural?

And is the case sensitivity that big of a deal?

If I give in to the all plural routes convention, the case sensitivity
issue isn’t a big deal at all. Using my CamelCase preferences is as
simple as:

scope :path_names => { :new => “New”, :edit => “Edit” } do

  resources :movies, :path => "Movies"

end

Kevin
http://www.RawFedDogs.net
http://www.WacoAgilityGroup.org
Bruceville, TX

What’s the definition of a legacy system? One that works!
Errare humanum est, ignoscere caninum.

I don’t think it matters if the conventions make sense or not. If
possible, you should try to use them for the following reasons:

  1. If another programmer who is familiar with Rails starts maintaining
    your site, they will be annoyed that they have to figure out what you
    did instead of already knowing how it works.

  2. If you have a subtle problem and ask this list, no one will have
    any idea how to fix it because no one else will have done it your way.

  3. If you start maintaining another Rails site, you will have to learn
    the convention anyway, so why learn two conventions?

  4. The next version of Rails might change something that breaks your
    site.

On Wed, Apr 27, 2011 at 03:08:50PM -0500, Kevin M. wrote:

In that context, which of:

/Recipes/Beef-Brisket

/Recipe/Beef-Brisket

After sending my last reply, I thought of another way of looking at
the above URLs. Using slugs and Rails plural default, and my
CamelCase preferences, a single recipe for beef brisket would be
displayed at:

/Recipes/Beef-Brisket

But, looking at the above URL, folks not knowing about Rails defaults
would expect to find two or more recipes for beef brisket at the above
URL. With the singular:

/Recipe/Beef-Brisket

it’s a little clearer that it’s for a single recipe.

Kevin
http://www.RawFedDogs.net
http://www.WacoAgilityGroup.org
Bruceville, TX

What’s the definition of a legacy system? One that works!
Errare humanum est, ignoscere caninum.

Phil

On Wed, Apr 27, 2011 at 3:46 PM, Kevin M.
[email protected]wrote:

CamelCase preferences, a single recipe for beef brisket would be
it’s a little clearer that it’s for a single recipe.

I guess I’ve never looked at it that way. To me, I look at the url
“recipes/beef-brisket”, and I assume I am in the part of the website
which
lists recipes, and that I am looking at one particular recipe, the one
for
beef-brisket. That seems perfectly natural, even without familiarity
with
rails conventions.

I can understand having preferences, but I’m not certain I see the worth
in
fighting all the Rails conventions; if I were to switch to django or to
cake-php or (something else), I’d think it would make more sense for me
to
adopt the conventions of those frameworks than to make my life more
difficult by spending half my time working around the default
assumptions…
But that’s just me. :slight_smile:

On Wed, Apr 27, 2011 at 08:14:01PM -0500, Phil C. wrote:

I can understand having preferences, but I’m not certain I see the
worth in fighting all the Rails conventions; if I were to switch to
django or to cake-php or (something else), I’d think it would make
more sense for me to adopt the conventions of those frameworks than
to make my life more difficult by spending half my time working
around the default assumptions… But that’s just me. :slight_smile:

Good point. Another take on the above might be that one should try a
few frameworks and find a framework with conventions that mesh well
with one’s preferences. That’s the reason I moved on from Rails the
last time I tried it.

Kevin
http://www.RawFedDogs.net
http://www.WacoAgilityGroup.org
Bruceville, TX

What’s the definition of a legacy system? One that works!
Errare humanum est, ignoscere caninum.

I’ll chime in on this thread a little –

As someone learning Rails, the most frustrating thing is not that these
conventions exist - it’s that it’s very hard to figure out what those
conventions are through anything but experimentation and banging one’s
head against it.

This is where I think the documentation could help more. The guides,
railscasts, and whatnot are good for figuring out how one piece works,
or
how to do one particular thing - but it’s hard to get a notion of the
big
picture, exactly how all the pieces hook together, and what
customization
points are available to change things.

Something like “The default ActionController::TestCase class assumes
that
it’s testing a class with the same name as it, but with the word “Test”
lopped off the end. To change this, do x.” But all in one place, not
littered through API docs.

On Apr 27, 2:04pm, Kevin M. [email protected] wrote:

Is there a way to configure RESTful routes to use plural collection
routes and singular member routes? For the moment I have all of my
routes mapped separately via match statements but I’d like to find an
easier way, especially if/when I get to a point where nested resources
would come in handy.

I didn’t see anyone in this thread answer your actual, original
question on here so I figured I’d chime in. I’m not familiar with the
Rails 3 routes syntax yet, but I think in Rails 2.x this should be as
simple as:

map.resources :recipes
map.connect ‘Recipe/:id’, :controller => ‘recipe’, :action => ‘show’

That should tie the route you want into the conventional controller
method, which should allow both to exist in harmony, which means you
can use all the normal conventions for restful items from the
controller down; all this should do in effect is point your ~custom~
routing URL to the RESTful show action. Note that a few things I
haven’t shown which you’ll likely want are:

  1. An override on def self.find for the Recipe model to search by ID
    or by permalink
  2. An override of to_param to output the name instead of ID for
    permalinking.
  3. Possibly a helper to generate your desired URLs in your views, such
    as def permalink_recipe_path(name) …; I haven’t tried it but you
    might be able to name the route above to accomplish this, something
    like

map.permalink_recipe ‘Recipe/:id’, :controller => ‘recipe’, :action
=> ‘show’

But I’m not sure how exactly that works with passing in a parameter.
I’d start with the URL mapping, and see when the normal redirects and
what not get you to a URL you don’t like.

\Peter

\Peter,

On Thu, Apr 28, 2011 at 09:15:05AM -0700, Peter wrote:

I didn’t see anyone in this thread answer your actual, original
question on here so I figured I’d chime in. I’m not familiar with the
Rails 3 routes syntax yet, but I think in Rails 2.x this should be as
simple as:

map.resources :recipes
map.connect ‘Recipe/:id’, :controller => ‘recipe’, :action => ‘show’

Actually, I think I just found the trick for Rails 3 in section 2.5 of
the routing guide - Singular Resources. It looks like RESTful routes
tailored to my preferences are as simple as:

  resource :recipe, :path => "Recipe"

  match 'Recipes' => 'recipes#index', :as => :recipes, :via => :get

I had tried using singular resources before but mistakenly typed
resources instead of resource.

Kevin
http://www.RawFedDogs.net
http://www.WacoAgilityGroup.org
Bruceville, TX

What’s the definition of a legacy system? One that works!
Errare humanum est, ignoscere caninum.

On Apr 28, 12:33pm, Kevin M. [email protected] wrote:

resources instead of resource.
On Apr 28, 12:33pm, Kevin M. [email protected] wrote:

Hmm, mapping a singular resource should expose routes that don’t
accept an ID, which isn’t really what you want; in other words there
should be /recipe which points to the singular recipe in the system,
but in reality you have multiple recipes and want to take an ID. I’m
not sure what that match line is doing so perhaps that’s patching
things up, but I’d be worried you’ll hit issues like recipe_path won’t
expect an ID (since its a singular route). Although experimentation
is the king, so if its working go with it; if you hit ~unexpected~
issues then this might be the cause.

2c,
\Peter