I'm refactoring my app's routes to address the rule of thumb because my routes are very lengthy.
Imagine that I have the following models
class Company < ApplicationRecord
has_many :projects
has_many :users
...
end
class Project < ApplicationRecord
belongs_to :company
has_many :jobs
...
end
...
and my routes look like
Rails.application.routes.draw do
...
resources :companies do
resources :projects do
resources :jobs
end
end
end
After the user's logged in, I set the @current_user
and the companies that he has access to - @current_user.companies
. With this approach, I avoid hitting the database when users tempered the URL to access unauthorized resources. For example, when a user edits a job:
/companies/1/projects/30/jobs/20/edit
class JobsController < ApplicationController
def edit
@project = @company.projects.find(params[:project_id])
@job = @project.jobs.find(params[:job_id])
...
end
...
end
I followed the example from guides and added scope with a prefixed named parameter to shorten one level of nested resources.
scope ':company_id' do
resources :projects do
resources :jobs
end
end
So far so good, I had successfully shortened my URLs from
/companies/1/projects/30/jobs/20/edit
edit_company_project_job_path(@company, @project, @job)
to
/1/projects/30/jobs/20/edit
edit_project_job_path(@company, @project, @job)
But then I broke my form_with model: [@company, @project, @job]
because it fails to infer prefixed named parameter - :compay_id
, even when I specify it @company.id
.
The only solution I come with was setting the named route back again
scope ':company_id' as: 'company' do
resources :projects do
resources :jobs
end
end
Isn't It the same as before? I just shorted the URL /1/projects/30/jobs/20/edit
but the path is back to the original edit_company_project_job_path(@company, @project, @job)
. Am I missing something? I'd love to know how you do it
They key is to use the :as
attribute when specifying the scope. This will make it work as expected with form_with
and other helpers that rely on url_for
.
I just submitted a documentation update Pull Request to Rails for this.