Devise - creating users only by admin - ruby-on-rails

I'm creating an app where I need only admins to create new users:
routes.rb:
devise_for :users, :skip => [:registrations]
resources :users
root 'dashboard#index'
users_controller.rb
# GET /users/1/edit
#def edit
#
#end
# POST /users
# POST /users.json
def create
build_resource(sign_up_params)
respond_to do |format|
if resource.save
format.html { redirect_to user_path(resource), notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: user }
else
clean_up_passwords resource
respond_with resource
end
end
end
When I open http://localhost:3000/users/new
I got this error:
AbstractController::ActionNotFound at /users/new
Could not find devise mapping for path "/users/new".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
What is wrong there? Thank you a lot!

The problem is that you're confusing Devise functionality with that of your app:
#config/routes.rb
resources :users #-> nothing to do with devise
When you create a user, you're using the devise build_resource helper. Problem being that this will require devise functionality, which is not going to happen for users_controller.
To use sign_up_params or build_resource, you'll have to scope your routes to a devise controller (so all the available session data is there)...
#config/routes.rb
devise_for :user, skip: [:registrations]
devise_scope :user do
resources :users, path: "", only: [:new, :create], controller: "registrations" #-> url.com/users/new
end
This way, you'll be able to override the standard Devise::RegistrationsController with your own code:
#app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
before_action :authenticate_user!
before_action :check_admin
def create
build_resource(sign_up_params)
...
end
private
def check_admin
redirect_to root_path unless current_user.admin?
end
end
--
What I would recommend is either removing the Devise functionality from your users controller, or overriding the registrations controller so that only an admin can create a user (which it seems you're trying to do already).

Related

Rails API - No route matches [POST]

I am experimenting the Rails API with devise.
I am trying to create a POST request so that the user can autenticate using the email and password. To do so, I am using devise and simple token authentication
However, when I submit my POST request using postman, I get the error:
ActionController::RoutingError (No route matches [POST] "/v1/sessions"):
I think the issue is that is sending the post to: /v1/sessions rather than api/v1/sessions.
However, I do not understand why since I declared my routes such as: api-->v1-->sessions
Folder structure of controller
Routes
Rails.application.routes.draw do
# devise_for :users
namespace :api do
namespace :v1 do
resources :sessions, only: [:create, :destroy]
end
end
end
Controller
class V1::SessionsController < ApplicationController
def create
user = User.where(email: params[:email]).first
if user&.valid_password?(params[:password])
render json: user.as_json(only: [:email, :authentication_token]), status: :created
else
head(:unauthorized)
end
end
def destroy
end
end
shoud it be class Api::V1::SessionsController < ApplicationController instead?

devise_scope in namespaces, rails api_only mode

I'm trying to remove the obsolete routes of devise, in my api_only rails setup. However i'm in a fuss about how to define them properly with devise_scope. I have the following routes.rb:
# config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :users do
devise_scope :user do
resource :confirmations, only: %i[create show], format: false
end
end
end
end
Which refers to the confirmations_controller that contains custom json renders instead of the typical respond_with:
# app/controllers/api/users/confirmations_controller.rb
module Api
module Users
class ConfirmationsController < Devise::ConfirmationsController
# POST /resource/confirmation
def create
self.resource = resource_class.send_confirmation_instructions(resource_params)
yield resource if block_given?
if successfully_sent?(resource)
# respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name))
render json: { status: 201 }, status: :created
else
# respond_with(resource)
render json: { status: 422, errors: resource.errors.keys },
status: :unprocessable_entity
end
end
# GET /resource/confirmation?confirmation_token=abcdef
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
yield resource if block_given?
if resource.errors.empty?
set_flash_message!(:notice, :confirmed)
# respond_with_navigational(resource) { redirect_to after_confirmation_path_for(resource_name, resource) }
render json: { status: 200 }, status: :ok
else
# respond_with_navigational(resource.errors, status: :unprocessable_entity) { render :new }
render json: { status: 422, errors: resource.errors.keys },
status: :unprocessable_entity
end
end
end
end
end
As can be seen in the routes.rb I only need the create and show endpoints of confirmations. However the current definition results in the following error when running rspec:
Failure/Error: get api_users_confirmations_path, params: { confirmation_token: 'incorrect_token' }
AbstractController::ActionNotFound:
Could not find devise mapping for path "/api/users/confirmations?confirmation_token=incorrect_token".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
Which tends mostly to the missing devise mapping, considering that the devise_scope is defined properly. However i'm not sure how to solve this properly without having to include the bindings in every devise controller. Is this doable from the routes?
I have never tried to use resources inside of devise_scope.
This is how I have defined it.
devise_scope :user do
delete 'logout', to: 'devise/sessions#destroy'
end
This is how I have defined in one of my application
devise_for :users, path: 'api/v1/accounts', controllers: {
:registrations => 'api/v1/accounts/registrations',
:sessions => 'api/v1/accounts/sessions',
:passwords => 'api/v1/accounts/passwords'
}
devise_scope :user do
get '/sessions/new' => "sessions#new", :as => :new_sessions
get '/sessions/forgot_password' => "sessions#forgot_password", :as => :forgot_password
post '/validate_referral_code' => 'validates#validate_referral_code', as: :validate_referral_code
post '/validate_employment_code' => 'validates#validate_employment_code', as: :validate_employment_code
post '/get_weather' => 'temperature#weather', as: :weather
get '/fetch' => 'zip_codes#fetch', as: :fetch_zip_code
post '/request_demo' => 'demos#create', as: :create
end
namespace :api do
namespace :v1 do
scope :accounts do
resources :third_party_logins, only: [] do
collection do
get :action_name
end
end
end
end
end

Redirecting to the devise controller after successfull login

I am new in Ruby On Rails. I am making an application using devise gem. My requirement is after logged in successfully I should redirect to devise controller again.
I have created devise controller as 'Users'
I have created one more controller home_controller.rb for redirecting
under home controller I have coded this.
def index
if user_signed_in?
redirect_to :controller => 'users', :action =>add
end
end
I have written add method under users_controller.rb
And under routes.rb I have coded this
devise_for :users, controllers:{sessions: "users/sessions"}
root :to => 'home#index'
match 'users/:action' => 'users#add', :as => :add
But its not redirecting. What should I do. any help. Thanks
Try this:-
resources :users do
member do
get "add"
end
end
If I understand correctly, you'll want to use the Devise redirect helpers:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
user_add_path
end
end
I don't understand is this:
I should redirect to devise controller again
Devise controllers are split into SessionsController, RegistrationsController, PasswordsController, ConfirmationsController & UnlocksController.
Which one would you like to redirect to?
My hunch, and this is strengthened after reading your comments, is you want to redirect to the UsersController, like this:
#config/routes.rb
resources :users, only: :show do
get :add
end
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def add
//declarations here
end
def show
//declarations here
end
end
This should help you

Rails Routing Error on Email Confirmation

I am new to rails and I am trying to add a email confirmation upon register. I currently get this error.
(Bonus points for any verbose and easily understood answer.)
Routing Error
No route matches {:action=>"edit", :controller=>"email_activations", :id=>false}
config/routes.rb
LootApp::Application.routes.draw do
get "password_resets/new"
get "sessions/new"
resources :users
resources :sessions
resources :password_resets
resources :email_activations
root to: 'static_pages#home'
app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
def registration_confirmation(user)
#user = user
mail(:to => user.email, :subject => "registered", :from => "alain#private.com")
end
end
app/controllers/email_activations_controller.rb
class EmailActivationsController < ApplicationController
def edit
#user = User.find_by_email_activation_token!(params[:id])
#user.email_activation_token = true
redirect_to root_url, :notice => "Email has been verified."
end
end
app/views/user_mailer/registration_confirmation.html.haml
Confirm your email address please!
= edit_email_activation_url(#user.email_activation_token)
resources keyword in rails routes is a magical keyword that creates 7 restful routes by default
edit is one of those
check these docs link
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
edit expects to edit a record so requires a id to find the record for editing
in your case
you can just add a custom action in users controller
like
in UsersController
def accept_invitation
#user = User.find_by_email_activation_token!(params[:token])
#user.email_activation_token = true
redirect_to root_url, :notice => "Email has been verified."
end
in routes.rb
resources :users do
collection do
get :accept_invitation
end
end
in app/views/user_mailer/registration_confirmation.html.haml
accept_invitation_users_url({:token=>#user.email_activation_token})
Check out how to add custom routes here
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions

Routing Error Try running rake routes

I got 2 diferents message but whit the same error, Im using a devise for users... Here is my routes.rb
Estaciones::Application.routes.draw do
root :to => "static_pages#home"
match '/contact', :to=>'static_pages#contact'
match '/about', :to=>'static_pages#about'
devise_for :users
resources :users
whit my routes.rb just like that i got the next error
uninitialized constant UsersController
Try running rake routes for more information on available routes.
but if a remove the "resourses: users" i got the following error
No route matches [GET] "/users/27"
I put my UsersController
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to user_session_path
else
redirect_to new_user_session_path
end
end
def show
#user = User.find(params[:id])
#redirect_to #user
end
end
The filename for your users model must be users_controller.rb and be in the controllers folder.

Resources