I have the following statement in routes:
resource :users, :only => [:index, :show, :update, :destroy] do
get "users/dashboard"
end
However, when I do rake routes, I got:
dashboard_users GET /users/users/dashboard(.:format) users/users#dashboard
users GET /users(.:format) users#show
PUT /users(.:format) users#update
DELETE /users(.:format) users#destroy
Note that users_path was incorrectly mapped to users#show. I was expecting:
users GET /users/:id/(.:format) users#show
What might cause this issue and how I can fix it?
you should use resources instead of resource. e.g.
resources 'users'
the difference between resource and resources is:
resource is for operations for a single model. when using resource model, there's no "index" action.
see: http://guides.rubyonrails.org/routing.html
further more, I notice that your route is a bit strange. if you just want to add an action named 'dashboard' with GET accessing method, just declare like this:
resources 'users' do
get :dashboard
end
Instead of doing this
resource :users, :only => [:index, :show, :update, :destroy] do
get "users/dashboard"
end
Do this
namespace :dashboard do
resource :users, :only=>[:index,:show,:udpate,:destroy]
end
I think this will work for you.
Related
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.
Let's say I have
resources :users, only: %i[new create edit update]
I would like to change typical /users/new to /signup.
Code like below is ugly.
resources :users, only: %i[create edit update]
get '/signup', to: 'users#new'
Is there a better (cleaner) way to do it?
EDIT: Seems like it's the best way that there is. Guess grouping is the only way to keep it readable.
As far as I'm aware the best you're going to be able to do is
resources :users, only: [:new], path_names: { new: "sign_up" }, path: '/'
resources :users, only: [:create, :edit, :update]
which at least makes it easier to tell that 'sign_up' is part of the users resource. If you're fine with /users/sign_up you can do it in one line, but wanting to get rid of the /users part makes this trickier.
If you wanted to keep them organized and do not mind the route being "/users/signup" then this will work.
resources :users, only: %i[create edit update] do
get 'signup', to: :new, on: :collection, as: :signup
end
Then rake routes
signup_users GET /users/signup(.:format) users#new
users POST /users(.:format) users#create
edit_users GET /users/:id/edit(.:format) users#edit
users PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
I have a rails api application where I am using Devise gem for user management. I created a user model off the devise gem. After that, I noticed that I have two same routes listed in the rake routescommand. I want POST (/users) to call api/v1/users#create action first and then call devise/registrations#create.
user_registration POST /users(.:format) devise/registrations#create
api_users POST /users(.:format) api/v1/users#create {:format=>:json}
When I test POST (/users) using users_controller_spec file, api/v1/users#create action is called. However, when I do a POST (/users) using POSTMAN, the logs indicates that devise/registrations#createaction is called instead.
How do I correct this so that the POST (/users) I do using POSTMAN or curl calls api/v1/users#create first to create the user model and then calls devise/registrations#create to register the user?
I am not 100% sure how devise works so any help here would be helpful.
This is my config/routes.rb
Rails.application.routes.draw do
devise_for :users
# Api definition
namespace :api, defaults: { format: :json }, path: '/' do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
# We are going to list our resources here
resources :users, only: [:show, :create, :update, :destroy]
resources :sessions, only: [:create, :destroy]
end
end
end
So, the thing with Rails Routes is, when you make a request, routes are checked as they are defined in the routes.rb from top to bottom.
Now, when you make a request via POSTMAN, the /users path matches with a path generated via devise_for, as it is the first line in the file.
Now, when you are writing tests for the controller, you are not really accessing /users, you are just telling the api/v1/users_controller to invoke the create method, which is bound to hit the api/v1/users#create
Now, a way you can resolve this conflict is by changing what devise names its routes. If you do something like this:
Rails.application.routes.draw do
devise_for :users, path: 'customer'
# Api definition
namespace :api, defaults: { format: :json }, path: '/' do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
# We are going to list our resources here
resources :users, only: [:show, :create, :update, :destroy]
resources :sessions, only: [:create, :destroy]
end
end
end
This is what the devise routes will be:
new_user_session GET /customer/sign_in(.:format) devise/sessions#new
user_session POST /customer/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /customer/sign_out(.:format) devise/sessions#destroy
user_password POST /customer/password(.:format) devise/passwords#create
new_user_password GET /customer/password/new(.:format) devise/passwords#new
edit_user_password GET /customer/password/edit(.:format) devise/passwords#edit
...
I am using Ruby on Rails 4.2 and I would like to route "nested" paths by using namespace or scope :module / scope :path within the block of a resource.
That is, I have the following route:
resources :users, :only => [:show]
that matches
user_path GET /users/:id(.:format) users#show
I would like to match the following paths
users_sessions_path POST /users/sessions users/sessions#create
user_session_path GET /users/:id/session users/sessions#show
delete_user_session_path GET /users/:id/session/delete users/sessions#delete
user_session_path DELETE /users/:id/session users/sessions#destroy
I read the official documentation and I tried to state something like
resources :users, :only => [:show] do
scope :module => :users do
scope :module => :sessions do
# scope :path => :sessions do
# namespace :sessions do
...
end
end
end
but no attempt has been successful. How should I state routes?
Update after the #dgilperez answer
I tried the following code
resources :users, :only => [:show] do
scope :module => :users do
resource :session, :only => [:show, :new, :create, :destroy] do
get :delete, :on => :collection, :to => 'sessions#delete'
end
end
end
that matches
delete_user_session_path GET /users/:user_id/session/delete(.:format) users/sessions#delete
new_user_session_path GET /users/:user_id/session/new(.:format) users/sessions#new
user_session_path POST /users/:user_id/session(.:format) users/sessions#create
user_session_path GET /users/:user_id/session(.:format) users/sessions#show
DELETE /users/:user_id/session(.:format) users/sessions#destroy
but I still need to map new and create actions without needing to pass the :user_id parameter. That is, I would like to map something like
new_user_session_path GET /users/session/new(.:format) users/sessions#new
user_session_path POST /users/session(.:format) users/sessions#create
I think you are overcomplicating it: you don't need to use scope or path to render nested resources. You just nest them:
resources :users, :only => [:show] do
resources :sessions
end
will render the following routes:
user_sessions GET /users/:user_id/sessions(.:format) sessions#index
POST /users/:user_id/sessions(.:format) sessions#create
new_user_session GET /users/:user_id/sessions/new(.:format) sessions#new
edit_user_session GET /users/:user_id/sessions/:id/edit(.:format) sessions#edit
user_session GET /users/:user_id/sessions/:id(.:format) sessions#show
PATCH /users/:user_id/sessions/:id(.:format) sessions#update
PUT /users/:user_id/sessions/:id(.:format) sessions#update
DELETE /users/:user_id/sessions/:id(.:format) sessions#destroy
user GET /users/:id(.:format) users#show
Those are not the routes you mention you need, but I'd like you to reconsider if you really need them like that, with namespaced controllers and custom names such as delete_user_ or you prefer to go more standard. If you really need those exact routes, let me know.
UPDATE after OP's update
To get the two routes missing you need to get them out the rested resource. I'd just write them directly like this:
resources :users, :only => [:show] do
scope :module => :users do
resource :session, :only => [:show, :destroy] do
get :delete, :on => :collection, :to => 'sessions#delete'
end
end
end
get 'users/session/new', to: 'users/sessions#new', as: :new_user_session
post 'users/session', to: 'users/sessions#create'
I am using Ruby on Rails 3.0.7 and in my application I have an Users::Article class (note that it is namespaced). In the routes.rb file it is stated as follow:
resources :users do
resources :articles
end
I would like to set the route related to the Users::Article class so that I can access that at the URL /articles, /articles/new, /articles/1 and /articles/1/edit but I would like to still use the RoR Convention over Configuration "system". That is, I would like to use:
Users::ArticlesHelper;
views/users/articles/<file_name>.html.erb view files;
named routes (<name>_path and <name>_url);
and others "a là Ruby on Rails Way"...
How can I do that?
In few words, for example, I would like to refer to the /articles/1 path but making the application to work exactly as it is considering the users/<user_id>/articles/1 path.
it's not an estetic matter, but it's related to parameters for routing.
you can use /articles/:id and then refer to the owner (User) inside controller.
in the second case /users/:user_id/articles/:id will pass 2 params to controller.
From the ActionDispatch::Routing::Mapper::Resources docs:
:shallow
# Generates shallow routes for nested resource(s). When placed on a parent
# resource, generates shallow routes for all nested resources.
resources :posts, :shallow => true do
resources :comments
end
# Is the same as:
resources :posts do
resources :comments, :except => [:show, :edit, :update, :destroy]
end
resources :comments, :only => [:show, :edit, :update, :destroy]
# This allows URLs for resources that otherwise would be deeply nested such as a
# comment on a blog post like /posts/a-long-permalink/comments/1234 to be
# shortened to just /comments/1234.
To get this from >rake routes
users_articles GET /articles(.:format) {:action=>"index", :controller=>"users/articles"}
POST /articles(.:format) {:action=>"create", :controller=>"users/articles"}
new_users_article GET /articles/new(.:format) {:action=>"new", :controller=>"users/articles"}
edit_users_article GET /articles/:id/edit(.:format) {:action=>"edit", :controller=>"users/articles"}
users_article GET /articles/:id(.:format) {:action=>"show", :controller=>"users/articles"}
PUT /articles/:id(.:format) {:action=>"update", :controller=>"users/articles"}
DELETE /articles/:id(.:format) {:action=>"destroy", :controller=>"users/articles"}
We need this in our routes.rb
namespace :users, :path => '' do
resources :articles
end
Note: I am using :namespace as that is what you stated.
Hope this helps.