I am using the rails_best_practices gem which tells me i have an error:
overuse route customizations (customize_count > 8)
resources :stores do
collection do
get :api
end
member do
get :printer
get :delete
get :inventory
delete :inventory
get :daysheet
get :detailed_daysheet
get :labels
patch :restore
patch :print_labels
post :daysheet
end
end
Resulting in these paths:
api_stores_path GET /stores/api(.:format) stores#api
printer_store_path GET /stores/:id/printer(.:format) stores#printer
delete_store_path GET /stores/:id/delete(.:format) stores#delete
inventory_store_path GET /stores/:id/inventory(.:format) stores#inventory
daysheet_store_path GET /stores/:id/daysheet(.:format) stores#daysheet
detailed_daysheet_store_path GET /stores/:id/detailed_daysheet(.:format) stores#detailed_daysheet
labels_store_path GET /stores/:id/labels(.:format) stores#labels
DELETE /stores/:id/inventory(.:format) stores#inventory
restore_store_path PATCH /stores/:id/restore(.:format) stores#restore
print_labels_store_path PATCH /stores/:id/print_labels(.:format) stores#print_labels
POST /stores/:id/daysheet(.:format) stores#daysheet
After refactoring, I need it to still function as it does now with get routes such as /stores/7/inventory and /stores/18/printer
How can i compress these get routes to accomplish the same routing goals?
One approach would be to do:
resources :stores do
scope module: :stores do
resource :printer, only: [:show]
resource :daysheet, only: [:show, :create]
resource :detailed_daysheet, only: [:show]
resource :inventory, only: [:show, :destroy]
resources :labels, only: [:index]
resources :print_labels, only: [:update]
resource :restore, only: [:update]
end
collection do
get :api
end
member do
get :delete
end
end
Which gives you:
store_printer GET /stores/:store_id/printer(.:format) stores/printers#show
store_daysheet GET /stores/:store_id/daysheet(.:format) stores/daysheets#show
POST /stores/:store_id/daysheet(.:format) stores/daysheets#create
store_detailed_daysheet GET /stores/:store_id/detailed_daysheet(.:format) stores/detailed_daysheets#show
store_inventory GET /stores/:store_id/inventory(.:format) stores/inventories#show
DELETE /stores/:store_id/inventory(.:format) stores/inventories#destroy
store_labels GET /stores/:store_id/labels(.:format) stores/labels#index
store_print_label PATCH /stores/:store_id/print_labels/:id(.:format) stores/print_labels#update
PUT /stores/:store_id/print_labels/:id(.:format) stores/print_labels#update
store_restore PATCH /stores/:store_id/restore(.:format) stores/restores#update
PUT /stores/:store_id/restore(.:format) stores/restores#update
api_stores GET /stores/api(.:format) stores#api
delete_store GET /stores/:id/delete(.:format) stores#delete
stores GET /stores(.:format) stores#index
POST /stores(.:format) stores#create
new_store GET /stores/new(.:format) stores#new
edit_store GET /stores/:id/edit(.:format) stores#edit
store GET /stores/:id(.:format) stores#show
PATCH /stores/:id(.:format) stores#update
PUT /stores/:id(.:format) stores#update
DELETE /stores/:id(.:format) stores#destroy
Naturally, this requires that you create a number of new, nested controllers, such as Stores::Printers which will reside in app/controllers/stores/printers_controller.rb. But, you're now using standard RESTful routes, which I guess some people thing is a good thing.
Also, for your nested routes, you'll have :store_id in the params instead of id.
That collection api and member delete still seem odd, but I'm not sure what the intention is there.
Related
In my routes.rb file, I have the following code:
Rails.application.routes.draw do
get 'getTodos', to: 'todos#get'
get 'getUsers', to: 'users#get'
get 'getStates', to: 'states#get'
post 'addTodo', to: 'todos#add'
post 'addUser', to: 'users#add'
delete 'deleteTodo/*id', to: 'todos#delete'
delete 'deleteUsers/*IDs', to: 'users#delete'
delete 'deleteAllTodos', to: 'todos#delete_all'
put 'updateTodo', to: 'todos#update'
end
How can I modify this code to make it more beautiful and correct?
The biggest issue with this code is that its completely unidiomatic. In Rails you create, read, update and destroy (CRUD) resources through the following routes:
HTTP Method Path Controller#Action
GET /todos(.:format) todos#index
POST /todos(.:format) todos#create
GET /todos/new(.:format) todos#new
GET /todos/:id/edit(.:format) todos#edit GET /todos/:id(.:format) todos#show
PATCH /todos/:id(.:format) todos#update
PUT /todos/:id(.:format) todos#update
DELETE /todos/:id(.:format) todos#destroy
The key here is the combination of the HTTP method and path.
GET /todos gets you all the todos while GET /todos/:id shows you a specific resource.
GET /todos/new displays the form to create a new todo. POST /todos actually creates the resource from a form submission.
GET /todos/:id/edit displays the form to edit a todo. PATCH /todos/:id actually updates the resource from a form submission.
DELETE /todos/:id - You should be able to guess what this does.
You can generate these routes with:
Rails.application.routes.draw do
resources :todos
end
If you want to define a routes that deletes all the todos RESTfully it should be defined as DELETE /todos (without an id).
Rails.application.routes.draw do
resources :todos do
delete '/', on: :collection, action: :destroy_all
end
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
See:
Rails Routing from the Outside In
I would do something like this. Try to use default Rails REST actions instead of overwriting them
Rails.application.routes.draw do
resources :todos, only: [:index, :create, :update, :destroy] do
collection do
delete :delete_all, to: 'todos#delete_all'
end
end
resources :users, only: [:index, :create, :destroy]
resources :states, only: :index
im currently trying to use the resource but one problem im having , that when i do the following
resource :orders
the route /orders dosent route to OrdersController#index rather it points to the show action of the controller, how can i fix this issue ?
becuase of this problem im having to do this which i feel is kinda hack and not good
get '/orders', to: 'orders#index'
get '/orders/:id', to: 'orders#show'
this is my routes.rb file
Rails.application.routes.draw do
get '/carts', to: 'carts#index'
get '/payments', to: 'payments#index'
post '/payments', to: 'payments#add_credits'
get '/orders', to: 'orders#index'
get '/orders/:id', to: 'orders#show'
resources :users do
resource :orders, only: %i[show create index]
resource :carts, only: %i[create destroy], path: 'cart', as: 'cart'
end
resource :sessions, only: [] do
post 'login', action: :create
post 'logout', action: :destroy
get 'login', action: :new
end
resources :products
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
thanks for your answer :)
Don't use
resource :orders
use
resources :orders
You would only use resource when the item orders is a single entity in your application... which is to say you're using the plural to refer to that one item.
Move the resource for orders outside of the Users routes.
Just and FYI, you can have both the full resource outside of Users and then those restricted routes inside Users, but I'm not sure what the goal is here so it is up to you to decide that.
Rails.application.routes.draw do
get '/carts', to: 'carts#index'
get '/payments', to: 'payments#index'
post '/payments', to: 'payments#add_credits'
resources :orders
resources :users do
resource :orders, only: %i[show create index] <-- not sure if this remains here
resource :carts, only: %i[create destroy], path: 'cart', as: 'cart'
end
...
I have some nested nested resources:
resources :assessments do
member do
get 'result'
end
resources :respondents, only: [:new, :create] do
collection do
post "invite", to: :invite_all
get "invite", to: :new_invite
end
end
end
For the line resources :respondents, only: [:new, :create] is it possible to set the action for the new and crate actions? You can use to: to set the action for a single resource. I'd like to avoid writing match statements if I can and keep things resourceful.
What motivates me to ask this is I'd like to be able to specify the action for a nested resource rather than have it route to the child resource's action. For example:
If I define
resources :assessments do
resources :respondents
end
the path /assessments/:id/respondents/new will route to respondents#new. The problem with this it forces me to add logic to the new action to determine if the route contains the assessment id or not and then render the correct view. I'd like to be able to send the nested resource to a different action. Is there a "rails way" to do this?
Why not just not nest the resources like this:
resources :assessments do
member do
get 'result'
end
end
resources :respondents, only: [:new, :create] do
collection do
post "invite", to: :invite_all
get "invite", to: :new_invite
end
end
Or to keep nesting for other actions (e.g. index) just define the new and create actions separately.
resources :assessments do
member do
get 'result'
end
resources :respondents
end
resources :respondents, only: [:new], path_names: { new: 'make' } do
collection do
post :generate
post "invite", to: :invite_all
get "invite", to: :new_invite
end
end
This will create these routes:
result_assessment GET /assessments/:id/result(.:format) assessments#result
assessment_respondents GET /assessments/:assessment_id/respondents(.:format) respondents#index
POST /assessments/:assessment_id/respondents(.:format) respondents#create
new_assessment_respondent GET /assessments/:assessment_id/respondents/new(.:format) respondents#new
edit_assessment_respondent GET /assessments/:assessment_id/respondents/:id/edit(.:format) respondents#edit
assessment_respondent GET /assessments/:assessment_id/respondents/:id(.:format) respondents#show
PATCH /assessments/:assessment_id/respondents/:id(.:format) respondents#update
PUT /assessments/:assessment_id/respondents/:id(.:format) respondents#update
DELETE /assessments/:assessment_id/respondents/:id(.:format) respondents#destroy
assessments GET /assessments(.:format) assessments#index
POST /assessments(.:format) assessments#create
new_assessment GET /assessments/new(.:format) assessments#new
edit_assessment GET /assessments/:id/edit(.:format) assessments#edit
assessment GET /assessments/:id(.:format) assessments#show
PATCH /assessments/:id(.:format) assessments#update
PUT /assessments/:id(.:format) assessments#update
DELETE /assessments/:id(.:format) assessments#destroy
generate_respondents POST /respondents/generate(.:format) respondents#generate
invite_respondents POST /respondents/invite(.:format) respondents#invite_all
GET /respondents/invite(.:format) respondents#new_invite
new_respondent GET /respondents/make(.:format) respondents#new
This way you get new and create outside of of nested assessments.
I created these routes real quick locally and this is what was generated when running rake routes.
I've read in the past that nesting multiple resources is not good practice.
I've got models, Hotel, Room, and Visit. (H has_many R, R has many V)
If you're not supposed to nest this many times, like below...
resources :hotels do
resources :rooms do
resources :visits
end
end
then what is the best practice?
I would like to be able to retrieve all the visits for a specific room via something like room/3/visits... but I would be unable to do that currently as the above code would break best practice nesting.
Shallow Nesting
"One way to avoid deep nesting (as recommended above) is to generate the collection actions scoped under the parent, so as to get a sense of the hierarchy, but to not nest the member actions."
See Rails Guide on Routing Section 2.7.2 Shallow Nesting for more information
In your case, you'd be looking at:
resources :hotels do
resources :rooms, shallow: true
end
resources :rooms, only: [] do
resources :visits
end
this is equivalent to:
resources :hotels do
resources :rooms, only: [:index, :new, :create]
end
resources :rooms, only: [:show, :edit, :update, :destroy]
and would provide you with the following routes:
GET /hotels/:hotel_id/rooms(.:format) rooms#index
POST /hotels/:hotel_id/rooms(.:format) rooms#create
new_hotel_room GET /hotels/:hotel_id/rooms/new(.:format) rooms#new
edit_room GET /rooms/:id/edit(.:format) rooms#edit
room GET /rooms/:id(.:format) rooms#show
PATCH /rooms/:id(.:format) rooms#update
PUT /rooms/:id(.:format) rooms#update
DELETE /rooms/:id(.:format) rooms#destroy
hotels GET /hotels(.:format) hotels#index
POST /hotels(.:format) hotels#create
new_hotel GET /hotels/new(.:format) hotels#new
edit_hotel GET /hotels/:id/edit(.:format) hotels#edit
hotel GET /hotels/:id(.:format) hotels#show
PATCH /hotels/:id(.:format) hotels#update
PUT /hotels/:id(.:format) hotels#update
DELETE /hotels/:id(.:format) hotels#destroy
room_visits GET /rooms/:room_id/visits(.:format) visits#index
POST /rooms/:room_id/visits(.:format) visits#create
new_room_visit GET /rooms/:room_id/visits/new(.:format) visits#new
edit_room_visit GET /rooms/:room_id/visits/:id/edit(.:format) visits#edit
room_visit GET /rooms/:room_id/visits/:id(.:format) visits#show
PATCH /rooms/:room_id/visits/:id(.:format) visits#update
PUT /rooms/:room_id/visits/:id(.:format) visits#update
DELETE /rooms/:room_id/visits/:id(.:format) visits#destroy
I have below routes
resources :analytics do
collection do
get 'group_image'
get 'group_tag'
get 'group_location'
get 'group_time'
end
end
But it also creates default routes, which I don't need. How can I limit routes here?
You can do this:
resources :analytics, only: [] do
collection do
get 'group_image'
get 'group_tag'
get 'group_location'
get 'group_time'
end
end
It will creates your custom routes, but not the default one.
just use namespace instead of resources:
namespace :analytics do
get 'group_image'
get 'group_tag'
get 'group_location'
get 'group_time'
end
You can define like this also by excluding default actions.
resources :analytics, :except => [:new, :create, :destroy, :index] do
collection do
get 'group_image'
get 'group_tag'
get 'group_location'
get 'group_time'
end
end