I am newish to Ruby on Rails, using version 4.1 in a project.
I am a bit confused about the way the nested resources are working in rails. Perhaps someone can help.
I am building a tasking system as a learning project.
I have websites that have tasks that belong to them. When viewing tasks, I can do:
resources :websites do
resources :tasks
end
And a link will take me to my task just fine, with a url like http://myapp.com/websites/2/tasks/3
<%= link_to 'Show', website_task_path(website,task) %>
What I noticed though, is that I can change the website id in the url to anything - http://myapp.com/websites/what-the-hell-is-going-on-here/tasks/1 - works just the same as the other link. Or I can access that task with a different website id in the url as well.
So the question is, is Rails supposed to do anything with that piece of information by default? Is it up to me if I want to make sure that you are accessing the task with the right parent resource in the parameters?
Your task's ID is unique in the tasks table. As long as you want to show, edit or delete a task, this information is enough. You can easily get the parent through your association. But a nested resource allows you to create new tasks. In this case there is no ID set. You need to know the correct parent to set it on your task.
Excerpt from a possible TasksController:
class TasksController < ApplicationController
before_action :set_website, only: [:create]
def create
@website.tasks.create!(task_params)
end
private
def set_website
@website = Website.find(params[:website_id])
end
def task_params
params.require(:task).permit(:title, :text)
end
end
Generated nested routes:
# Routes without :task_id - Parent matters!
website_tasks
GET /websites/:website_id/tasks(.:format) tasks#index
POST /websites/:website_id/tasks(.:format) tasks#create
new_website_task
GET /websites/:website_id/tasks/new(.:format) tasks#new
# Routes with :task_id - Parent redundant.
edit_website_task
GET /websites/:website_id/tasks/:id/edit(.:format) tasks#edit
website_task
GET /websites/:website_id/tasks/:id(.:format) tasks#show
PATCH /websites/:website_id/tasks/:id(.:format) tasks#update
PUT /websites/:website_id/tasks/:id(.:format) tasks#update
DELETE /websites/:website_id/tasks/:id(.:format) tasks#destroy
You can clean the routes from the redundant website_id by using shallow nesting. This is explained in detail in the Rails docs.
Basically it means:
resources :website do
resources :tasks, only: [:index, :new, :create]
end
resources :tasks, only: [:show, :edit, :update, :destroy]
Which is the same as writing:
resources :websites do
resources :tasks, shallow: true
end
There may be some use cases where the full path is valuable, e. g. you want to feed it to a search engine or you want the URL to be more speaking for readers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With