This stems from the open PR #15719 on Collection Routing.
That PR is very big and adds many new features to Rails, so I'd like to follow a conservative approach and add one feature at the time, making sure it's fully tested and backwards-compatible.
The first feature is to change the match of a path like GET /posts/1,3,4
:
- currently, Rails matches to
posts#show
with the params set toid: "1,3,4"
- the idea is instead to match to
posts#index
with the params set toids: ["1", "3", "4"]
.
Feedback required: do you think this is a valuable feature to add to Rails, independently of the other PR?
To achieve this goal and be backwards-compatible, I propose we add a new :subset
boolean option to the resources
method.
If you don't specify the option, and simply write resources :posts
in config/routes.rb
, then the current routing behavior remains, that is:
$ rake routes
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
...
If instead you specify the option, and write resources :posts, subset: true
, the routes change to:
$ rake routes
Prefix Verb URI Pattern Controller#Action
posts GET /posts(/:ids)(.:format) posts#index {:ids=>/.?,.?/}
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
...
Feedback required: what do you think of this :subset
parameter? What about its name?
step-1.diff is the code required for this change.
The next step is to clearly identify the Regex that would make the router switch between index
and show
. For instance:
/posts
=> index/posts/1
=> show (params:{id: "1"}
)/posts/1,2
=> index (params:{ids: ["1", "2"]}
)/posts/,
=> ???/posts/1,
=> ???/posts/,2,,
=> ??
Feedback required: what do you think the regex should be?
In my opinion, it can simply be /.?,.?/
, that is, if you have specified subset: true
, then whenever you have a comma in your parameter, it means the parameter is an array of ids, and you want to hit the index
action.
The last step is to tell the router then, in case of subset, we want the parameters to be returned as an Array, not as a String.
For instance, GET /posts/1,3,4
should match posts#index
with parameters {"ids"=>["1", "3", "4"]}
, and not {"ids"=>"1,3,4"}
.
In other words, GET /posts/1,3,4
should be equivalent to GET /posts?ids[]=1&ids[]=3&ids[]=4
.
To achieve this, the router must somehow know that:
1,3,4
comes from a path that accepts subsets (and it's not simply an ID with commas in it)- the
,
(comma) character is used to separate items in the subset
Feedback required: what is the best way to achieve this?
I wrote some code in step-2.diff which achieves the desired result, but I'm not sure whether storing the Regex in the Journey::Router
module and then accessing it from Routing::Mapper
is the best way to do this
Also my next PR that is coming out soon rewrites the DSL mapper using resource route objects. Routes would be implemented as objects so that each route knows about its type when parsing the options.