Closed andrewculver closed 1 week ago
Looking at https://github.com/bullet-train-co/bullet_train/blob/main/test/system/super_scaffolding/super_scaffolding_test.rb, it looks like we don't have a test for this scenario so it makes sense that it's either always been broken or has been broken by refactors.
Just making notes as I look into this.
With this incorrect placement mentioned above we get routes like this:
$ rails routes | grep included | grep -v avo | sort
DELETE /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#destroy
PATCH /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#update
POST /account/milestones/:milestone_id/included_tasks(.:format) account/projects/milestones/included_tasks#create
PUT /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#update
account_milestone_included_tasks GET /account/milestones/:milestone_id/included_tasks(.:format) account/projects/milestones/included_tasks#index
account_milestones_included_task GET /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#show
new_account_milestone_included_task GET /account/milestones/:milestone_id/included_tasks/new(.:format) account/projects/milestones/included_tasks#new
edit_account_milestones_included_task GET /account/milestones/included_tasks/:id/edit(.:format) account/projects/milestones/included_tasks#edit
reorder_account_milestone_included_tasks POST /account/milestones/:milestone_id/included_tasks/reorder(.:format) account/projects/milestones/included_tasks#reorder
reorder_account_project_milestones_included_tasks POST /account/projects/:project_id/milestones/included_tasks/reorder(.:format) account/projects/milestones/included_tasks#reorder
With the correct placement we get:
rails routes | grep included | grep -v avo | sort
DELETE /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#destroy
PATCH /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#update
POST /account/projects/milestones/:milestone_id/included_tasks(.:format) account/projects/milestones/included_tasks#create
PUT /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#update
account_milestones_included_task GET /account/milestones/included_tasks/:id(.:format) account/projects/milestones/included_tasks#show
edit_account_milestones_included_task GET /account/milestones/included_tasks/:id/edit(.:format) account/projects/milestones/included_tasks#edit
account_projects_milestone_included_tasks GET /account/projects/milestones/:milestone_id/included_tasks(.:format) account/projects/milestones/included_tasks#index
new_account_projects_milestone_included_task GET /account/projects/milestones/:milestone_id/included_tasks/new(.:format) account/projects/milestones/included_tasks#new
reorder_account_project_milestones_included_tasks POST /account/projects/:project_id/milestones/included_tasks/reorder(.:format) account/projects/milestones/included_tasks#reorder
reorder_account_projects_milestone_included_tasks POST /account/projects/milestones/:milestone_id/included_tasks/reorder(.:format) account/projects/milestones/included_tasks#reorder
@andrewculver I could use a little more context on why some of these routes get generated like they do.
I've read these two articles, but am still not grocking it all. https://blog.bullettrain.co/rails-model-namespacing/ https://blog.bullettrain.co/nested-namespaced-rails-routing-examples/
Please note that I'm not trying to argue that we should do things differently, I'm just trying to understand why we do things the way we do. I know you've spent a lot of time on this problem space, so I assume there are good reasons. I just need to understand them to be effective in making changes around this stuff.
To try to simplify and get at my basic questions I'm using just these two scaffolding commands that you mentioned above:
bin/rails generate super_scaffold Project Team name:text_field
bin/rails generate super_scaffold Projects::Milestone Project,Team name:text_field
Those commands leave us with these declared routes for milestones
:
resources :projects do
scope module: 'projects' do
resources :milestones, only: collection_actions
end
end
namespace :projects do
resources :milestones, except: collection_actions
end
Which results in these URL paths:
$ rails routes | grep milestones | grep -v avo | grep -v api | sort
DELETE /account/projects/milestones/:id(.:format) account/projects/milestones#destroy
PATCH /account/projects/milestones/:id(.:format) account/projects/milestones#update
POST /account/projects/:project_id/milestones(.:format) account/projects/milestones#create
PUT /account/projects/milestones/:id(.:format) account/projects/milestones#update
account_project_milestones GET /account/projects/:project_id/milestones(.:format) account/projects/milestones#index
account_projects_milestone GET /account/projects/milestones/:id(.:format) account/projects/milestones#show
new_account_project_milestone GET /account/projects/:project_id/milestones/new(.:format) account/projects/milestones#new
edit_account_projects_milestone GET /account/projects/milestones/:id/edit(.:format) account/projects/milestones#edit
Some of these make sense to me, and are exactly what I'd expect.
POST /account/projects/:project_id/milestones(.:format) account/projects/milestones#create
account_project_milestones GET /account/projects/:project_id/milestones(.:format) account/projects/milestones#index
new_account_project_milestone GET /account/projects/:project_id/milestones/new(.:format) account/projects/milestones#new
But then there are these, and I don't understand why we'd want a bare /projects/
segment in the URL that doesn't come with a matching :project_id
.
DELETE /account/projects/milestones/:id(.:format) account/projects/milestones#destroy
PATCH /account/projects/milestones/:id(.:format) account/projects/milestones#update
PUT /account/projects/milestones/:id(.:format) account/projects/milestones#update
account_projects_milestone GET /account/projects/milestones/:id(.:format) account/projects/milestones#show
edit_account_projects_milestone GET /account/projects/milestones/:id/edit(.:format) account/projects/milestones#edit
Why would we not want the paths to be more like this? (Isn't that the recommendation/convention for shallow routing?)
DELETE /account/milestones/:id(.:format) account/projects/milestones#destroy
PATCH /account/milestones/:id(.:format) account/projects/milestones#update
PUT /account/milestones/:id(.:format) account/projects/milestones#update
account_projects_milestone GET /account/milestones/:id(.:format) account/projects/milestones#show
edit_account_projects_milestone GET /account/milestones/:id/edit(.:format) account/projects/milestones#edit
@andrewculver - Ok, after struggling with this for a while I think something finally clicked and I figured out the answer to my question.
I think the deal is that for URL paths like /account/projects/milestones/:id
the /projects/
segment doesn't have anything to do with the Project
model it's a reference to the namespace on the Projects::Milestone
model & controller. And so from a "shallow routes" perspective that is a shallow route because it only references one type of model. It just happens to be a model with a namespace that has the same URL segment (aka /projects/
) that the parent model has. Which made it confusing.
Just to illustrate by using a different namespace. Say that instead of Projects::Milestones
you did Foo::Milestones
like this:
bin/rails generate super_scaffold Project Team name:text_field
bin/rails generate super_scaffold Foo::Milestone Project,Team name:text_field
Then the path to a Foo::Milestone
would be /account/foo/milestones/:id
.
I think the problem is going to be in this file somewhere, but I haven't quite figured out where.
I think generally what's happening is that we just look for the first instance of a block for the parent namespace and then cram everything into it. I think we'll probably have to do something like looking for the first instance and the last instance and then cram the appropriate bits into each one. (And if they happen to be the same block then it'll get both.)
When super scaffolding the following resources:
We produce the following error when trying to show a
Projects::Milestone
athttp://localhost:3000/account/projects/milestones/:id
:This is because the routes weren't properly generated for this combination of namespacing and nesting.
Super scaffolding currently produces:
But it should have produced: