In my application, a User can make a Post, and a User can make Correction (think of it as a comment) on another user's post. Each User can have many Posts, and each Post can have many Corrections.
On each show page for a Post, there is a form to create a new Correction. This uses the user_post_corrections path.
On the show page for each User, I would like to display each Correction they've submitted for any Post. This requires a user_corrections path.
In order to achieve this, I have the following in my routes.rb:
resources :users do
resources :posts do
resources :corrections
end
end
resources :users do
resources :corrections
end
This intuitively feels bad to me, as I've created two nested routes that are very similar to one another.
Is there a better way to do this? My code is working fine as it is but is there a best practice method for implementing this kind of model?
Routing concerns are an excellent but underused tool for DRYing out your routes:
concern :correctable do
resources :corrections
end
# just an example of multiple concerns
concern :commentable do
resources :comments
end
resources :users, concerns: :correctable
resources :posts, concerns: [:correctable, :commentable]
However you should take when creating nested routes so that you are not nesting needlessly.
Often you might want the collective actions [new, index, create] to be scoped by the parent:
GET|POST /posts/:post_id/corrections
GET /posts/:post_id/corrections/new
While you want the member actions to be unscoped since you can always access a record directly if it has a unique id.
GET /corrections/:id
GET /corrections/:id/edit
PATCH /corrections/:id
DELETE /corrections/:id
To do this you would declare the routes like so:
resources :corrections, only: [:show, :update, :edit]
concern :correctable do
resources :corrections, only: [:new, :index, :create]
end
resources :users, :posts, concerns: [:correctable]
The shallow: true option does something like this but does not work well when you declare the same resources several times as it adds unscoped routes for every call.
Related
I have the following routes defined:
resources :users do
resources :suggestions do
post :make, on: :collection
end
end
I would like to tell resources :suggestions not to create any of the 7 default actions because I don't need them right now. With :only and :except I can limit the number of those actions being created, but I don't seem to figure how to create none of them.
Indeed, I could just leave the resources out and just define my :make route, but I would like to benefit from the automatic nesting and param handling, as well as leave a door open for a future need of several of the 7 default actions.
Hope this is helpful:-
resources :suggestions, only: [] do
end
I have a resource blog.
I have a namespace admin that can create, see, delete blogs.
app/controllers/admin/blogs_controller.rb
Admin have its own portal
The route is pretty standard:
namespace :admin do
resources :blogs
end
and a standard user that have another portal and can just see the blogs and see the details of one blog.
I just implemented two methods in app/controllers/main_controller that look just like the index and show methods of Admin::BlogsController.
The route is:
get '/main/blog' => 'main#blog'
get '/main/blog/:id' => 'main#blog_show'
How can I improve my design?
is this solution which are you looking for?
namespace :admin do
resources :blogs
end
namespace :main do
resources :blogs, only: [:show, :index]
end
app/controllers/admin/blogs_controller.rb
Admin::BlogsController
app/controllers/main/blogs_controller.rb
Main::BlogsController
I am working on this project that has products and under products I have cars and trucks and each have comments and the ability to vote on both the car model and comments. The car models all work correctly but the trucks model does not have the correct routes. I am thinking it has something to do with having comments shallow, but honestly, I am not sure what I am doing wrong. Any guidance would be appreciated.
resources :products do
resources :cars do
member { post :vote }
resources :car_comments, shallow: true do
member { post :vote }
end
end
resources :trucks do
member { post :vote }
resources :truck_comments, shallow: true do
member { post :vote }
end
end
end
UPDATE
After looking over one of the controller files, I found the error and now the routes work as expected. However, I still feel that my routes look clunky, and since there will be more models, boats, tractors, etc, I dont think the way the routes are written now will hold up.
I believe it is because you are using resources :trucks, when you use the resouces it calls the CRUD methods. if you want certain routes you need to specify them, for example: resources :trucks, only: [:create, :destroy]
So far I have my routes like this: ( out of learning purposes I am curious to get it working with nested resources technique, but if you think this will get too complicated please feel free to suggest any other way of routing technique too)
resources :management, only: [:show] do
resources :report, only: [:show], controller: 'report' do
member do
# hmm what to write in here?!
end
end
end
my GOAL is to have a URL like this:
/managment/SOME_ID_WE_PASS_/report
/managment/1/report
But still can't figure out how exactly to write that route? Can you please take a look?
You don't need nested resources.
resources :crowd_management, only: [:show] do
get :exec_report, on: :member
end
That will produce:
/crowd_management/:id mapped to CrowdManagementController#show
/crowd_management/:id/exec_report mapped to CrowdManagementController#exec_report
The helper methods will be:
crowd_management_path
exec_report_crowd_management_path
You can run rake routes for a detailed list of all your routes.
The goal is to create a URL like this for a GET, REST API:
/manager/someID/report
example: /manager/2/report
I can get it to show in rake routes if do it this way:
get 'manager/:id/report', to: 'report#show'
But in some weblogs I read, thats the way unskilled developers write their routes! and looks like the better way is to use "nested resources" so I am banging my head over desk to get nested resources working the same way...but no success
this is what I have written so far:
resources :manager, only: [:show] do
resources :report, only: [:show], controller: 'report' do
member do
## WAT ?!
end
end
end
First, you might want to consider reading different blogs if they're calling routes like that "unskilled".
What you proposed is actually fine considering it's a non-standard RESTful route, and maybe even preferable in some cases. If you want an alternative approach, you have a couple different options. I don't think any one is more right than the other, but I prefer the first because it takes up less vertical space.
resources :manager, only: [:show] do
get 'report' => 'report#show', on: :member
end
or
resources :manager, only: [:show] do
member do
get 'report' => 'report#show'
end
end