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
...
Related
It used to work but after some changes, Action Controller is catching an exception
Routing Error: No route matches [GET] "/clock_events/1/clock_in"
routes.rb file:
Rails.application.routes.draw do
root to: 'clock_events#index'
get '/register', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
get '/logout', to: 'sessions#destroy'
resources :clock_events, except: [:destroy] do
member do
post 'clock_in', to: 'clocks#clock_in'
post 'clock_out', to: 'clocks#clock_out'
end
end
resources :users, except: [:destroy]
end
You've defined clock_in with the post http verb, here:
resources :clock_events, except: [:destroy] do
member do
post 'clock_in', to: 'clocks#clock_in'
post 'clock_out', to: 'clocks#clock_out'
end
end
But, you're trying to use the get verb, as indicated here:
Routing Error: No route matches [GET] "/clock_events/1/clock_in"
You need to either change your path to use the get verb:
resources :clock_events, except: [:destroy] do
member do
get 'clock_in', to: 'clocks#clock_in'
post 'clock_out', to: 'clocks#clock_out'
end
end
Or modify your link (or whatever) to use the post method.
Also, your clock_in and clock_out actions are called on the clocks controller, not the clock_events controller, as indicated by your to: directive:
resources :clock_events, except: [:destroy] do
member do
post 'clock_in', to: 'clocks#clock_in'
post 'clock_out', to: 'clocks#clock_out'
end
end
Are you sure you don't want to use the ClockEventsController? If so, you could do:
resources :clock_events, except: [:destroy] do
member do
post :clock_in
post :clock_out
end
end
In which case you would get:
clock_in_clock_event POST /clock_events/:id/clock_in(.:format) clock_events#clock_in
clock_out_clock_event POST /clock_events/:id/clock_out(.:format) clock_events#clock_out
clock_events GET /clock_events(.:format) clock_events#index
POST /clock_events(.:format) clock_events#create
new_clock_event GET /clock_events/new(.:format) clock_events#new
edit_clock_event GET /clock_events/:id/edit(.:format) clock_events#edit
clock_event GET /clock_events/:id(.:format) clock_events#show
PATCH /clock_events/:id(.:format) clock_events#update
PUT /clock_events/:id(.:format) clock_events#update
How can I have a portion of a route Capitalized? For example I have a route scim/v2/user but I'd like it to be scim/v2/User (User capitalized). How can I achieve this while still using resource.
Routes file:
namespace :scim, defaults: { format: :json } do
namespace :v2 do
resource :user, only: [:create, :update, :show]
end
end
When I run $rake routes, I get this:
scim_v2_user POST /scim/v2/user(.:format) scim/v2/users#create {:format=>:json}
GET /scim/v2/user(.:format) scim/v2/users#show {:format=>:json}
PATCH /scim/v2/user(.:format) scim/v2/users#update {:format=>:json}
PUT /scim/v2/user(.:format) scim/v2/users#update {:format=>:json}
I'd like to either have the routes be /scim/v2/User or have them remain the same but have a way of mapping /scim/v2/User to /scim/v2/user.
By default resource wants a direct mapping between the resource name and the controller, but you can simplify use an upper case resource name and manually specify the controller to get around this:
namespace :scim, defaults: { format: :json } do
namespace :v2 do
resource :User, :controller => 'users', only: [:create, :update, :show]
end
end
Generates
Prefix Verb URI Pattern Controller#Action
scim_v2_User GET /scim/v2/User(.:format) scim/v2/users#show {:format=>:json}
PATCH /scim/v2/User(.:format) scim/v2/users#update {:format=>:json}
PUT /scim/v2/User(.:format) scim/v2/users#update {:format=>:json}
POST /scim/v2/User(.:format) scim/v2/users#create {:format=>:json}
I was able to solve this by manually specifying the path and controller. I specified that path should be Users (capitalized). Below is code in my routes file:
namespace :scim, defaults: { format: :json } do
namespace :v2 do
resources :user,
path: "Users",
controller: "users",
only: [:create, :update, :index, :show]
end
end
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 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.
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.