opaque urls for restful resources.

Hi,

in my current project I've got a couple of map.resources as such:

map.resources :quote_requests do |quote_request|    quote_request.resources :request_items end

Which yields urls like this:

/quote_requests/1/request_items/88

and url helpers like this:

edit_quote_request_path(my_quote_request)

What I wanted was to keep the url helpers as they were, but have a more opaque url, where the names in the url weren't directly tied to the names of my url helpers (you can already specify a different :controller, so that's already opaque). As in:

/quotes/1/items/88

I've written a *very* simple plugin that achieves this and I was wondering if it's something I should bother submitting as a patch - as in, am I the only one?

Here's what the map.resources calls would look like:

map.resources :quote_requests, :opaque_name => :quotes do |quote_request|    quote_request.resources :request_items, :opaque_name => :items end

And here's the contents of the plugin:

ActionController::Resources::Resource.module_eval <<'end_eval'    def path      @path ||= "#{path_prefix}/#{(options[:opaque_name] || plural).to_s}"    end end_eval

ActionController::Resources::SingletonResource.module_eval <<'end_eval'    def path      @path ||= "#{path_prefix}/#{(options[:opaque_name] || singular)}"    end end_eval

Any interest?

Regards, Trevor

Hi,

Nice plugin. See where you're coming from ... easier controller to table name (model) mapping to ease development, with a truncated public URL. Works great for HTML/JS content types, iow. REST app design without planned web service API. But I still prefer controller name -> table name mappings from a XML API perspective ... and it feels more natural when using ActiveResource.

- Lourens    http://blog.methodmissing.com

Hi,

this seem to be exactly what I need : I develop my controllers in english, but I want to display URL in french and keep my mappings in routes.rb as simple as possible.

Only one problem. I tried it and had to comment the last lines (SingletonResource module eval) : it's not working with the 1.2RC1 version. or maybe it's me : where did you put your code ? do you have to require some gem ?

Thanks for this patch

map.resources :quotes, :controller => 'quote_requests'

Or just call the controller QuotesController instead of QuoteRequestsController. Is this really so bad? I'd think having the shorter url and routes would be a plus.

Hey,

it's something that I did in edge rails - the 1.2 pre-releases don't have SingletonResource which is why you had to comment out that module_eval.

I think I'm going to have to release this as a plugin that I test against various rails versions because I'm pretty sure it's not a change that will appear in rails itself.

Trev

Hey,

comments inline:

Hi,

in my current project I've got a couple of map.resources as such:

map.resources :quote_requests do |quote_request|    quote_request.resources :request_items end

map.resources :quotes, :controller => 'quote_requests'

Or just call the controller QuotesController instead of QuoteRequestsController. Is this really so bad? I'd think having the shorter url and routes would be a plus.

Rick, you're absolutely right insofar as there's more than one way to skin this cat.

However, your suggestion to use the controller as a way to make the URL opaque will still leave the URL helpers as quote_path etc, which is not what I want - I want them to remain as quote_request_path etc.

And taking my example, I've also got quote_responses with response_items, and I want to have /responses/9/items/3 - which under your scheme would leave me with a clash between request_items and response_items URL helpers.

Of course, I could use name prefixes for my helpers and/or I can manually build my named routes, leaving map.resources behind.

However, map.resources is currently tightly coupling the interface (the URL elements) to the guts of my code and I want a more painless way to exert control over that. With this one-line change to resources.rb I can divorce the resource name in my code from the resource name in the URL.

Adding this option to two map.resources calls in my routes.rb I can change a url like:

/quotes/9/items/3

to

/anything/9/at_all/3

without *any* code changes (unless you had ActiveResource clients, in which case you'd have to change the name of your param for the resource entity in your controllers etc - a small change compared to the current alternatives).

I'm not saying anything is going to 'flop' without being able to easily make resource urls more opaque :slight_smile: but being able to do so has eased my pain and I think that others may benefit.

Trev

You know what, I'm going to comment in whatever order I please.... so here we go...

without *any* code changes (unless you had ActiveResource clients, in which case you'd have to change the name of your param for the resource entity in your controllers etc - a small change compared to the current alternatives).

Changing your own code involves a quick search/replace. Changing client code requires API breakage or deprecation. I'd rather have to change my own code.

However, map.resources is currently tightly coupling the interface (the URL elements) to the guts of my code and I want a more painless way to exert control over that. With this one-line change to resources.rb I can divorce the resource name in my code from the resource name in the URL.

I see your point in keeping the resource route that matches the resource/model name. I'm thinking something a little more clear than opaque_name would work better though:

map.resources :quotes,   :controller => 'quote_requests',   :named_route => 'quote_requests'

Hey,

You know what, I'm going to comment in whatever order I please.... so here we go...

without *any* code changes (unless you had ActiveResource clients, in which case you'd have to change the name of your param for the resource entity in your controllers etc - a small change compared to the current alternatives).

Changing your own code involves a quick search/replace. Changing client code requires API breakage or deprecation. I'd rather have to change my own code.

Absolutely - I too would rather change my own code... I just want to change less of it than I have to now. Unfortunately we're discussing hypothetical API changes - entirely my fault, I brought it up :stuck_out_tongue:

So there's hypothetical changes which would be made easier by :opaque_name (less search-and-replace) and others, perhaps more far-reaching, where it wouldn't make a blind bit of difference. The only concrete example I've got is the one I've given which you've correctly pointed out can be achieved without :opaque_name, albeit with a bit more effort.

Scroll down, there's more :slight_smile:

However, map.resources is currently tightly coupling the interface (the URL elements) to the guts of my code and I want a more painless way to exert control over that. With this one-line change to resources.rb I can divorce the resource name in my code from the resource name in the URL.

I see your point in keeping the resource route that matches the resource/model name. I'm thinking something a little more clear than opaque_name would work better though:

map.resources :quotes, :controller => 'quote_requests', :named_route => 'quote_requests'

There's two reasons I avoided approaching from this direction:

1 - At first glance it would require more changes to resources.rb - all usage of resource.singular and resource.plural in the map_X_actions methods would need checks for :named_route being present - or (more correctly) some refactoring would need to be applied. But my laziness helped me realize point #2:

2 - I view map.resources' first argument as the name of the resource as *I* know it. The name of the resource as *clients* know it can be altered using :opaque_name, vaguely analogous to ARes' collection_name attribute. So I want to say "map my resource called X and by the way, clients know it as Y". As such, your :named_route argument is not the same thing.

That said, if the argument name of :opaque_name is the major stumbling block I'll gladly change it to something more palatable - perhaps :resource_url_name or similar.

And thanks for taking the time to hash this out :slight_smile:

Trev

/quote_requests/1/request_items/88 [...] /quotes/1/items/88 [...] Any interest?

Trevor,

This is great!

Exactly what I was looking for!

Works ok with edge.

Victor