Devise invalid forgot password URL - ruby-on-rails

I have model User. And models
CaBase < User
LaUser < User
Both models has:
devise :database_authenticatable, :recoverable, :rememberable,
:trackable, :validatable
LaUser- Users that have access to Admin area.
CaBase - Users that has access only for front-end.
When I click on forgot password on CaBase login form, it mails me with link like:
site_name/admin/password/edit?reset_password_token=gtwSWQK8HH2-6p4CHp
But I need it to
site_name/password/edit?reset_password_token=gtwSWQK8HH2-6p4CHp
Also I have actions in ApplicationController
def after_sign_in_path_for(resource)
if resource.is_a?(LaUser)
admin_root_path
else
dashboard_index_path
end
end
def after_sending_reset_password_instructions_path_for(resource)
if resource.is_a?(LaUser)
admin_root_path
else
dashboard_index_path
end
end
What can I do with it?
UPD1:
get 'dashboard/index'
ActiveAdmin.routes(self)
devise_for :la_users, ActiveAdmin::Devise.config
devise_for :ca_base, path: '', path_names: {sign_in: 'login'}
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'welcome#index'
resource :ca_administrators, only: [:new, :create]

Problem was in that I don't checked which role have current user.
Code from Devise Mailer.
if record.is_a?(LaUser)
controller = 'active_admin/devise/passwords'
else
controller = 'devise/passwords'
end
edit_password_url = url_for(
controller: controller,
action: :edit,
reset_password_token: token
)

Related

Couldn't find User without an ID

Hi I am new to rails and I have just started making a facebook clone and I am starting out with the friends function, however I am getting the error ActiveRecord::RecordNotFound in UsersController#show Couldn't find User without an ID any help would be much appreciated
here is a picture of the error
users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!
before_action :set_user
def show
end
def friend
current_user.sent_follow_request_to(#user)
redirect_to root_path
end
def unfriend
current_user.unfollow(#user)
#user.unfollow(current_user)
redirect_to root_path
end
def accept
current_user.accept_follow_request_of(#user)
current_user.send_follow_request_to(#user)
#user.accept_follow_request_of(current_user)
redirect_to root_path
end
def decline
current_user.decline_follow_request_of(#user)
redirect_to root_path
end
def cancel
current_user.remove_follow_request_for(#user)
redirect_to root_path
end
private
def set_user
#user = User.find(params[:id])
end
end
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
followability
def unfollow(user)
followerable_relationships.where(followable_id: user.id).destroy_all
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
post 'users/:id/unfriend', to: 'users#unfriend', as: 'unfriend'
post 'users/:id/friend', to: 'users#friend', as: 'follow'
post 'users/:id/accept', to: 'users#accept', as: 'accept'
post 'users/:id/decline', to: 'users#decline', as: 'decline'
post 'users/:id/cancel', to: 'users#cancel', as: 'cancel'
get 'users/:id', to: 'users#show', as: 'users'
resources :users
root 'users#show'
# Define your application routes per the DSL in
https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
end
The problem is your root route:
root 'users#show'
You've defined your root web page, that is what will show up when the user requests /, as when they go to http://localhost:3000. It's set to the page which shows a specific user. This requires a User ID to do its job. But there is no ID provided.
Pick something else for your root page. users#index for example. Or your registration and sign on page. See the Devise docs for setting that up.

Devise reset password email points to the wrong controller

I included devise_token_auth to login from a webapp hosted elsewhere. But I'd like also to be able to sign in directly into my rails app.
My routes.rb looks like this:
#...
devise_for :users
namespace :api, defaults: {format: :json} do
mount_devise_token_auth_for 'User', at: 'auth'
#...
To reset the password the webapp sends a POST to /api/auth/password. With the configuration above, the link in the email to reset the password uses the wrong controller (the one on users/password). The redirect_url doesn't get applied and the user sees the login form of the rails app, not the webapp:
http://localhost:3000/users/password/edit?redirect_url=http://localhost:8080/reset_password&reset_password_token=...
If I comment the line devise_for :users the email link is correct, using api/auth/password/edit:
http://localhost:3000/api/auth/password/edit?redirect_url=http://localhost:8080/reset_password&reset_password_token=...
But of course, by commenting devise_for :users I can't login using just the rails app (on http://localhost:3000/users/sign_in).
Devise, on its mailer template to reset the password (reset_password_instructions.html.erb) calls onto the model to get the url:
<p><%= link_to 'Change my password', edit_password_url(#resource, reset_password_token: #token) %></p>
Although the controller that initially handled the client intent to reset the password was DeviseTokenAuth::PasswordsController, the function edit_password_url on User resolves to a path to be handled by Devise::PasswordsController (users/password/edit vs api/auth/password/edit).
The solution in this case was to use a different model:
routes.rb
#...
devise_for :users
namespace :api, defaults: {format: :json} do
mount_devise_token_auth_for 'Api::User', at: 'auth'
#...
api/user.rb
class Api::User < ActiveRecord::Base
devise :database_authenticatable, :recoverable,
:rememberable, :trackable, :validatable
include DeviseTokenAuth::Concerns::User
#...
end

How do you customize the route after a user logs-in or signs-in in Devise?

Currently, a user gets redirected to a root index page after sign-in/log-in but I want to customize it so that the redirect goes to a different page.
My route file is:
Rails.application.routes.draw do
devise_for :admins, path: 'admins'
root 'home#index'
get '/' => "courses#index", as: :user_root
devise_for :users, path: 'users'
resources :courses, :lessons
end
I understand that by default, the root become where the redirect goes to so I used the code get '/' => "courses#index", as: :user_rootand the redirect worked as I wanted to. However, when a user logs-out, the redirect tries to go to get '/' => "courses#index", as: :user_rootonce again which I do no want. Instead, I want the redirect when a user logs-out to go to root 'home#index'.
So essentially my question is how can I customize my root so I can achieve different redirects depending on whether a user logs-in/signs-in and logs-out?
You can use this:
class ApplicationController < ActionController::Base
private
def after_sign_in_path_for(resource)
user_root_path
end
def after_sign_out_path_for(resource_or_scope)
root_path
end
end
It is on devise wiki:
signing in
signing out

Devise - creating users only by admin

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).

Direct user on sign-in in devise rails

How do I direct a user to a specific page after they have successfully signed in with devise?
I have installed devise and as they stipulate I have added root to: 'home#index'which I assume roots to the page where sign-in is rendered. What I can't figure out, is how I redirect a user to an already existing specific page like 'graph/data' once they are signed in.
If you want to redirect the user only once then you can overwrite the after_sign_in_path method wich is described in the devise documentation
ref:
## application_controller.rb
def after_sign_in_path_for(resource)
sign_in_url = new_user_session_url
if request.referer == sign_in_url
super
else
stored_location_for(resource) || request.referer || root_path
end
end
If you want that the user will redirect to a specific route if the user is sign_in you can use devise_scope:
ref:
## routes.rb
devise_for :users
devise_scope :user do
authenticated :user do
root 'home#index', as: :authenticated_root
end
unauthenticated do
root 'devise/sessions#new', as: :unauthenticated_root
end
end
In addition to the the bulleric's answer:
At second case:
## routes.rb
devise_for :users
devise_scope :user do
authenticated :user do
root 'graphs#data', as: :authenticated_root
end
unauthenticated do
root 'home#index', as: :unauthenticated_root
end
end
But for this case You could have 'GraphsController' with action 'data'.
Additionaly, You should use ':authenticate_user!' into this. For example:
class GraphsController < ApplicationController
before_filter :authenticate_user!

Resources