Devise forgot password when nested - ruby-on-rails

My Rails 5 app running on Heroku uses Devise for auth and it is currently nested. Looks like this in routes.rb:
resources :teams do
member do
get :about
get :foundation
end
devise_for :users, :path_prefix => 'auth',
:controllers => {
:masquerades => "admin/masquerades",
:registrations => "registrations",
:sessions => "sessions",
:password => "passwords"
}
When I try to set up forgot password I get error after error with wrong routes because all standards from devise will point to new_user_session_path and not new_user_team_session_path.
Currently I get this error: undefined method new_user_session_path for <ActionDispatch::Routing::RoutesProxy:0x007fd6e50b1328>
My idea has been to generate the devise views and controllers and fix all the links. However, the current error does not appear in the passwords controller I took from the source: https://github.com/plataformatec/devise/blob/master/app/controllers/devise/passwords_controller.rb
My problem is this: I want to add a 'Reset password' feature and have nested Devise routes. How do I solve this?
EDIT:
Here is output from rake routes:
new_user_team_session GET /auth/users/teams/:team_id/sign_in(.:format) sessions#new
user_team_session POST /auth/users/teams/:team_id/sign_in(.:format) sessions#create
destroy_user_team_session DELETE /auth/users/teams/:team_id/sign_out(.:format) sessions#destroy
new_user_team_password GET /auth/users/teams/:team_id/password/new(.:format) devise/passwords#new
edit_user_team_password GET /auth/users/teams/:team_id/password/edit(.:format) devise/passwords#edit
user_team_password PATCH /auth/users/teams/:team_id/password(.:format) devise/passwords#update
PUT /auth/users/teams/:team_id/password(.:format) devise/passwords#update
POST /auth/users/teams/:team_id/password(.:format) devise/passwords#create
cancel_user_team_registration GET /auth/users/teams/:team_id/cancel(.:format) registrations#cancel
new_user_team_registration GET /auth/users/teams/:team_id/sign_up(.:format) registrations#new
edit_user_team_registration GET /auth/users/teams/:team_id/edit(.:format) registrations#edit
user_team_registration PATCH /auth/users/teams/:team_id(.:format) registrations#update
PUT /auth/users/teams/:team_id(.:format) registrations#update
DELETE /auth/users/teams/:team_id(.:format) registrations#destroy
POST /auth/users/teams/:team_id(.:format) registrations#create
back_user_team_masquerade_index GET /auth/users/teams/:team_id/masquerade/back(.:format) admin/masquerades#back
user_team_masquerade GET /auth/users/teams/:team_id/masquerade/:id(.:format) admin/masquerades#show
Cheers

Related

How to use Devise both in the site and in the Admin Pages

I'm new to RoR and Devise and i'm stuck in User Authentications with Devise. I'm developing a web site, which has admin pages in it. My structure looks like this:
app
|-controllers
|-admin
|- user_list_controller.rb //Every user crud operations are in it.
|-views
|-admin
|-user_list
|-new.html.erb
|-edit.html.erb
|-devise //Also have devise views
UserListController:
class Admin::UserListController < ApplicationController
layout 'admin/admin'
def index
#user_list = User.all
end
def new
#user = User.new
end
def edit
end
def delete
end
def create_user
end
end
What I want to do is that, I want to use Devise methods under this controller but this is where I stuck in. I created a UserController which base is Devise::RegistrationsController. But this time I got this error,
Could not find devise mapping for path "/admin/create_user". 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]
It looks like a route.rb error and my route file is:
Rails.application.routes.draw do
devise_for :users
devise_scope :user do
# post "admin/add_user" =>"admin/user_list#create_user", as: :adduser
end
namespace :admin do
root to: 'admin#index'
get 'user_list', :to => 'user_list#index'
post 'create_user', :to => "user#create"
get 'new_user', :to => 'user_list#new'
get 'user_proposals', :to => 'user_proposal_forms#index'
get 'user_appointments', :to => 'user_appointments#index'
get 'brands', :to => 'brands#index'
get 'brand_makes', :to => 'brand_makes#index'
get 'make_types', :to => 'make_types#index'
end
end
And the result of rake routes is this:
Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format)devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
admin_root GET /admin(.:format) admin/admin#index
admin_user_list GET /admin/user_list(.:format) admin/user_list#index
admin_create_user POST /admin/create_user(.:format) admin/user#create
admin_new_user GET /admin/new_user(.:format) admin/user_list#new
admin_user_proposalsGET /admin/user_proposals(.:format) admin/user_proposal_forms#index
admin_user_appointments GET /admin/user_appointments(.:format) admin/user_appointments#index
admin_brands GET /admin/brands(.:format) admin/brands#index
admin_brand_makes GET /admin/brand_makes(.:format) admin/brand_makes#index
admin_make_types GET /admin/make_types(.:format) admin/make_types#index
It looks messy, sorry for that. Finally my form_for looks like this:
<%= simple_form_for #user, url: admin_create_user_path, class: "form-horizontal" do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<% end %>
So where did I make a mistake? I've read all the documents in Devise, tried so many things but couldn't solve the problem.
In routes file use
devise_for :users, :controllers => { registrations: 'registrations' }

Devise routing issues with admin role

I'm trying to add Devise to an existing Rails 3.2.16 app.
I have the basics working, but I'd like to create an admin role that is able to edit any user profile without entering a password.
I used the code from Option 2 - Adding an admin attribute in the Devise Wiki "Add An Admin Role" section to set up the admin role.
My routes.rb has this:
devise_for :users, :controllers => { :registrations => :registrations }
scope "/admin" do
resources :users
end
This gives me the following routes
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format)devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) registrations#cancel
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
PUT /users(.:format) registrations#update
DELETE /users(.:format) registrations#destroy
admin_edit_user GET /admin/users/:id/edit(.:format) users/registrations#edit
users GET /admin/users(.:format) users#index
POST /admin/users(.:format) users#create
new_user GET /admin/users/new(.:format) users#new
edit_user GET /admin/users/:id/edit(.:format) users#edit
user GET /admin/users/:id(.:format) users#show
PUT /admin/users/:id(.:format) users#update
DELETE /admin/users/:id(.:format) users#destroy
The user views (devise/registrations/edit, etc) are hooked up correctly and work just fine, but the admin views are all pulled from the users folder (users/edit, etc), which means they bypass Devise.
For instance, my admin user edit form should probably have some variation on this in the form_for:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
but that code doesn't pull in any of the user data (all form fields are empty). The only way I can get it to show up is with the old code:
<%= form_for #user do |f| %>
Which then uses the update method from my users_controller, NOT from the Devise registrations_controller.
I've tried lots of variations on the routes because that seems to be key, but non of my attempts have worked. Help?
In order for your form_for helper to properly route your request through Devise, you need to declare your admin/users resource routes as Devise routes:
# config/routes.rb
devise_for :users, :controllers => { :registrations => :registrations }
scope "/admin" do
devise_for :users, :controllers => { :registrations => :registrations }
end
You'll continue to retain Devise functionality while being able to utilize the admin namespace for authorization purposes.

Rails add new view to devise

I have generated views with this command after I installed devise
rails generate devise:views
and I override registration controller by
class RegistrationsController < Devise::RegistrationsController
def sign_up2
end
end
And updated routes.rb with
devise_for :users, :controllers => { :registrations => "registrations" }
I expected to see a new route/view of
/users/sign_up2
but I don't see it
And here routes for devise
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) registrations#cancel
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
PATCH /users(.:format) registrations#update
PUT /users(.:format) registrations#update
DELETE /users(.:format) registrations#destroy
But I would like a new view and route
Update:
issue when I load view
First argument in form cannot contain nil or be empty
in this line
<%= form_for(resource, :as => resource_name,:html => { :class => "form-horizontal col-sm-12",:role=>"form"}, :url => user_registration_path(resource_name)) do |f| %>
Invoke a devise_scope block and declare your custom route within:
devise_for :users, :controllers => { :registrations => "registrations" }
devise_scope :user do
get "users/sign_up2"=> "users/registrations#sign_up2", :as => "sign_up2_registration"
end
The section on Configuring routes in the documentation provides the following explanation of devise_scope:
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is to create your routes normally and wrap them in a devise_scope block in the router
Previously, Devise allowed custom routes to be passed as a block to devise_for, but this behavior has been deprecated.
UPDATE:
To address the First argument in form cannot contain nil or be empty error, you need to ensure that your custom sign_up2 action is properly setting the resource variable. Assuming you want to mimic the registrations/new action, you can do something akin to the following:
def sign_up2
build_resource({})
respond_with self.resource
end
This ensures that the resource variable in your view is not nil and will not throw the exception you're currently witnessing.
Alternatively, depending on the behavior you're trying to evince, you can set your own instance variable in the custom controller action, then pass it as the resource to your form_for tag:
# app/controllers/users/registrations_controller.rb
def sign_up_2
#new_registrant = Registrant.new
end
# app/views/users/sign_up2.html.erb
<%= form_for(#new_registrant, :as => resource_name,:html => { :class => "form-horizontal col-sm-12",:role=>"form"}, :url => user_registration_path(resource_name)) do |f| %>
However, if you follow this approach, you should consider why you need to roll this into Devise. Devise, by default, assigns the resource variable via the build_resource function. If you're going to override/bypass this function, you should consider abstracting this entire functionality out of Devise since you're totally circumventing its default behavior.

Devise not obeying :path_names setting for sign_in route

I'm trying to setup Devise 3.1.0 with Rails 4.0.0.
I have configured my router like so:
devise_for :users,
:controllers => {
:registrations => 'users/registrations',
:sessions => 'users/sessions'
},
:path_names => {
:sign_in => 'login',
:sign_out => 'logout',
:sign_up => 'new'
}
new_user_session GET /users/login(.:format) users/sessions#new
user_session POST /users/login(.:format) users/sessions#create
destroy_user_session DELETE /users/logout(.:format) users/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel
user_registration POST /users(.:format) users/registrations#create
new_user_registration GET /users/new(.:format) users/registrations#new
edit_user_registration GET /users/edit(.:format) users/registrations#edit
PATCH /users(.:format) users/registrations#update
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
I've also turned on scoped views, and overridden the default views and registration controller:
# config/initializers/devise.rb
config.scoped_views = true
rails generate devise:views users
# app/controllers/users/registrations_controller.rb
#
# NOTE: I created this class, so creating new users could only be done by authenticated users.
#
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :authenticate_user!
prepend_before_filter :authenticate_scope!
skip_before_filter :require_no_authentication
end
# app/controllers/users/sessions_controller.rb
# (currently empty)
class Users::SessionsController < Devise::SessionsController
end
The problem:
Why devise is ignoring the :path_names settings above in some situations?
For example, this method will not use the :sign_in setting above, and returns an incorrect path:
new_session_path(resource_name)
=> /users/sign_in
resource_name
=> user
Whereas this method returns the correct path:
new_user_session_path
=> /users/login
The problem is, Devise internally uses the former method, and keeps redirecting to the wrong path when the user is not signed in.
Have I mis-configured something, or is Devise not working correctly? Could this be a Rails 4 issue?
I'm not sure what the issue I was having was. (I'd still be interested to know, if anyone knows).
But I've found another way to express what I wanted with devise, and it seems to work OK:
devise_for :users,
:controllers => {
:registrations => 'users/registrations'
},
:path_names => {
:sign_up => 'new'
}, :skip => [:sessions]
as :user do
get '/users/login' => 'devise/sessions#new', :as => :new_user_session
post '/users/login' => 'devise/sessions#create', :as => :user_session
match '/users/logout' => 'devise/sessions#destroy', :as => :destroy_user_session,
:via => Devise.mappings[:user].sign_out_via
end
I think you trying to solve your question with the wrong feature, in this link show you how to write another routes for devise, in my app I've recreated the routes with this:
devise_scope :user do
get '/cadastrar' => 'devise/registrations#new'
get '/entrar' => 'devise/sessions#new'
get '/editar' => 'devise/registrations#edit'
delete '/sair' => 'devise/sessions#destroy'
end
I'm glad if work!

Devise: edit_password_url in password reset email is sending users to url/api/v1/

I have my rails app and Devise set up to use a JSON API to do user registration and login. A side effect is that edit_password_url in the password reset email is accidentally sending users to:
http://localhost:3000/api/v1/password/edit?reset_password_token=ZzyPCgmspN2964ENUkSS
when it shouldn't have api/v1/, and should send them to:
http://localhost:3000/password/edit?reset_password_token=ZzyPCgmspN2964ENUkSS
I've been looking, but can't figure out where to fix this.
I've created the following:
Api::V1::SessionsController < Devise::SessionsController
and
Api::V1::RegistrationsController < RegistrationsController
I have a regular RegistrationsController that inherits from devise, but not a regular SessionsController, so I just inherit straight from devise there.
Thanks for the help!
EDIT:
routes.rb
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :users
devise_for :users, :path => '', path_names: {sign_in: "login", sign_out: "logout"},
controllers: { omniauth_callbacks: "authentications", registrations: "registrations"}
end
end
devise_for :users, :path => '', path_names: {sign_in: "login", sign_out: "logout"},
controllers: { omniauth_callbacks: "authentications", registrations: "registrations"}
resources :users
EDIT 2: rake routes output
new_api_v1_user_session GET /api/v1/login(.:format) api/v1/sessions#new {:format=>"json"}
api_v1_user_session POST /api/v1/login(.:format) api/v1/sessions#create {:format=>"json"}
destroy_api_v1_user_session DELETE /api/v1/logout(.:format) api/v1/sessions#destroy {:format=>"json"}
api_v1_user_omniauth_authorize GET|POST /auth/:provider(.:format) authentications#passthru {:provider=>/twitter|facebook/, :format=>"json"}
api_v1_user_omniauth_callback GET|POST /auth/:action/callback(.:format) authentications#(?-mix:twitter|facebook) {:format=>"json"}
api_v1_user_password POST /api/v1/password(.:format) api/v1/passwords#create {:format=>"json"}
new_api_v1_user_password GET /api/v1/password/new(.:format) api/v1/passwords#new {:format=>"json"}
edit_api_v1_user_password GET /api/v1/password/edit(.:format) api/v1/passwords#edit {:format=>"json"}
PUT /api/v1/password(.:format) api/v1/passwords#update {:format=>"json"}
cancel_api_v1_user_registration GET /api/v1/cancel(.:format) registrations#cancel {:format=>"json"}
api_v1_user_registration POST /api/v1(.:format) registrations#create {:format=>"json"}
new_api_v1_user_registration GET /api/v1/sign_up(.:format) registrations#new {:format=>"json"}
edit_api_v1_user_registration GET /api/v1/edit(.:format) registrations#edit {:format=>"json"}
PUT /api/v1(.:format) registrations#update {:format=>"json"}
DELETE /api/v1(.:format) registrations#destroy {:format=>"json"}
sessions GET /sessions(.:format) sessions#index
POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
edit_session GET /sessions/:id/edit(.:format) sessions#edit
session GET /sessions/:id(.:format) sessions#show
PUT /sessions/:id(.:format) sessions#update
DELETE /sessions/:id(.:format) sessions#destroy
authentications GET /authentications(.:format) authentications#index
POST /authentications(.:format) authentications#create
new_authentication GET /authentications/new(.:format) authentications#new
edit_authentication GET /authentications/:id/edit(.:format) authentications#edit
authentication GET /authentications/:id(.:format) authentications#show
PUT /authentications/:id(.:format) authentications#update
DELETE /authentications/:id(.:format) authentications#destroy
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session DELETE /logout(.:format) devise/sessions#destroy
user_omniauth_authorize GET|POST /auth/:provider(.:format) authentications#passthru {:provider=>/twitter|facebook/}
user_omniauth_callback GET|POST /auth/:action/callback(.:format) authentications#(?-mix:twitter|facebook)
user_password POST /password(.:format) devise/passwords#create
new_user_password GET /password/new(.:format) devise/passwords#new
edit_user_password GET /password/edit(.:format) devise/passwords#edit
PUT /password(.:format) devise/passwords#update
cancel_user_registration GET /cancel(.:format) registrations#cancel
user_registration POST / registrations#create
new_user_registration GET /sign_up(.:format) registrations#new
edit_user_registration GET /edit(.:format) registrations#edit
PUT / registrations#update
DELETE / registrations#destroy
EDIT 3:
So I've been testing some thing out, and in the devise email template, the path edit_password_url is there, and works to generate the above wrong url, but when I do rake routes, only edit_user_password_url exists.
Looking at the Devise Controller URL Helpers doc (found here), I would've used:
edit_password_path(:user) which translates to edit_user_password_path. path seems to be interchangeable with url.
I'm not 100% certain but this line defines a method called edit_password_path whereas this line creates a route in the Devise context...
You haven't posted your routes.rb but I am guessing you want /password/edit to route to 'Api/V1/RegistrationsController' without api/v1/ in URL?
If yes, then you need to use module option of routing DSL. like this:
scope module: 'api/v1/' do
resources :sessions, :registrations
end
Ofcourse you need to integrate the above in devise_for call. I am not a devise expert, I am guessing, you will need to use devise_scope instead of scope like this:
devise_scope module: 'api/v1/' do
resources :sessions, :registrations
end
Note: If the above doesn't work. Post back with your routes.rb. We will help you fix it
According to the routes that are generated you should try this. In my case its working fine. Try this:
edit_user_password_url(reset_password_token: #token)
So, strangely, I needed to change the path in the devise mailer template. I changed it from edit_password_url which worked to generate a url, but didn't show up in my rake routes output, to edit_user_password_url which I found in my rake routes output.
I would love to know why edit_password_url worked even though it doesn't show up in the rake routes output, and am more than happy to give assign the correct answer to someone who can explain what is going on to me.

Resources