Devise custom after_update_path_for not being called(Rails 4) - ruby-on-rails

I am using devise and want to specify different redirect after updating a user based on a conditional statement. I did follow this https://github.com/plataformatec/devise/wiki/How-To:-Customize-the-redirect-after-a-user-edits-their-profile and it is not calling my custom after_update_path_for method.
routes.rb
devise_for :users, :skip => [:registrations], :controllers => { :registrations => :registrations }
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users/:id' => 'devise/registrations#update', :as => 'user_registration'
end
The reason I have the skip registrations is because I do not wish to have the new and create routes for the user. I am not sure if the issue is with the routes or something else.
Here is the registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
protected
def after_update_path_for(resource)
binding.pry
if current_user.position == "owner" && current_user.sign_in_count == 1
hub_landing_path
end
end
end
Any help is greatly appreciated. This is really stumping me so if anyone has any ideas I would love to try them out.

You need to change
put 'users/:id' => 'devise/registrations#update', :as => 'user_registration'
to use your custom RegistrationsController controller. So it'll be:
put 'users/:id' => 'registrations#update', :as => 'user_registration'

The accepted answer by #NARKOZ does not work for me for Rails 4. I had to override the Devise Passwords controller like this:
# users/passwords_controller.rb
class Users::PasswordsController < Devise::PasswordsController
protected
def after_resetting_password_path_for(resource)
signed_in_root_path(resource)
end
end
There is documentation on this method here: https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in

Related

How to redirect to another page after devise sign in?

First, see my routes :
Rails.application.routes.draw do
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
devise_for :users, controllers: {
registrations: "registrations",
sessions: "sessions"
}
devise_scope :user do
authenticated :user do
root 'appointments#index', as: :authenticated_root
end
unauthenticated do
root 'sessions#new', as: :unauthenticated_root
end
match '/logout', :to => 'devise/sessions#destroy', via: :all
end
resources :appointments do
get :available_slots, on: :collection
resources :notes
resources :images, only: [:show]
end
#patch 'appointments/:id' => "appointments#update_status", as: :update_status
match 'appointments/:id/update_status' => "appointments#update_status", :via => :post
match 'appointments/:id/visited_patient_appointment' => "appointments#visited_patient_appointment", :via => :post
get 'archive' => "appointments#archive"
end
Now, how to redirect to appointments_path after user sign in? There is one devise method called after_sign_in_path_for(resource) which I override in Appointments Controller but still it is not working.
You trying to override in Appointments Controller which is wrong, it will be sessions_controller.rb or application_controller.rb
Try the following in the sessions_controller.rb or application_controller.rb
protected
def after_sign_in_path_for(resource)
stored_location_for(resource) || appointments_path
end
If not have stored_location then he will redirect to appointments_path
If you need to redirect all time to the same page like appointments_path then
protected
def after_sign_in_path_for(resource)
appointments_path
end
See the Devise wiki

Rails 4 - change URL from /user/:id to /:username

I have a controller pages#dashboard that I have set to be the user_root in my routes.rb
devise_for :users, controllers: { registrations: 'registrations' }
devise_scope :user do
get "/signup" => "devise/registrations#new"
get "/login" => "devise/sessions#new"
get "/logout" => "devise/sessions#destroy"
get "/:id" => "users#dashboard", :as => "user_root", :id => :username
end
I want the URL to be http://my_app.com/current_user_username
I have set the to_param in the user.rb model to:
def to_param
username
end
This works fine when I have a link such as:
<%= link_to "MY ACCOUNT", user_root_path(current_user) %>
But on initial login, the URL is: http://my_app.com/username (explicitly says 'username') instead of http://my_app.com/current_user_username
I have tried setting my to_param to:
def to_param
"#{username}"
end
and have also tried setting my route.rb to:
get "/:id" => "users#dashboard", :as => "user_root", :id => :username, :via => :get
Neither of these have solved the issue.
Environment: Rails 4.2.5, Ruby 2.3.0, Devise gem 3.5.3
Any help would be greatly appreciated.
You can simply add another route above everything in your routes.rb as:
get "/:username" => "users#dashboard", :as => "user_root"
devise_for :users, controllers: { registrations: 'registrations' }
devise_scope :user do
get "/signup" => "devise/registrations#new"
get "/login" => "devise/sessions#new"
get "/logout" => "devise/sessions#destroy"
get "/:id" => "users#dashboard", :as => "user_root", :id => :username
end
Then you need to find the user by something like this:
#user = User.find_by(username: params[:username])
Just use friendly_id:
#Gemfile
gem 'friendly_id', '~> 5.1'
$ rails generate friendly_id #-> generates initializer
$ rails generate scaffold user name:string slug:string:uniq #-> adds slug column
$ rake db:migrate
#app/models/user.rb
class User < ActiveRecord::Base
extend FriendlyId
friendly_id :username, use: [:slugged, :finders]
end
This will allow you to use the slug / username in lieu of the primary key:
<%= link_to current_user.username, user_path(current_user) #-> <a href="/users/john_jones" %>
You would not have to change your controller code etc for this to work.
--
Your routes can be simplified:
#config/routes.rb
resource :user, path: "", only: :show #-> url.com/:id to users#show
devise_for :users, controllers: { registrations: 'registrations' }, path_names: { sign_in: "login", password: "forgot", confirmation: "confirm", unlock: "unblock", sign_up: "", registration: "signup", sign_out: "logout" }
Whilst I don't know if you can use current_user inside your routes (I'm sure you can but I've not tested), you may wish to use /profile like this:
resource :profile, controller: :users, only: :show
This will send url.com/profile to the users#show action:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
current_user...
end
end
I solved this by adding this to application_controller.rb
def after_sign_in_path_for(resource)
user_root_path(current_user)
end
** This is a Devise specific answer.
Thanks to everyone who took the time to answer :)
I had a similar problem and made a few changes to routes and it worked here are the sets to do:
under User.rb model
def to_param
username
end
Routes:
resources :users, :path => '/' do
end
Controllers
#user=User.find_by_username(params[:id])
Views
link_to #user.username, #user.username.
Avoid user_path because it would redirect you to www.example.com/users/david
instead follow up this i have noted above
it will www.example.com/david this is better than the first.
hope anyone would be helped.

Secure certain route in rails

I have this in my routes file:
devise_for :users, :controllers => { :registrations => "users/registrations",
:sessions => "users/sessions",
:omniauth_callbacks => "users/omniauth_callbacks" }
devise_scope :user do
get 'sign_in', :to => 'users/sessions#new', :as => :new_user_session
get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
end
and now I added:
resources :users
because I want an admin user to be able to see all the users.
In CanCan I have this:
class Ability
include CanCan::Ability
def initialize(user)
if user
if user.admin?
can :manage, :all
end
can [:read, :edit, :update], User, :id => user.id
end
can [:create], User
end
end
Is this secure enough? Should I also add a before_filter in the UserController to block calls to the newly created route? Something like this? Problem with this is that users can't change their own profile anymore...
before_filter :check_rights
private
def check_rights
unless current_user.admin
redirect_to root_path
end
end
Found the solution. The before_filter is completely correct.
I had added
resources :users
before the devise part, you need to put it behind that part then users can still alter their own profile but can't go to index for example.

Ruby on Rails: not authorized to access sign up page?

I have devise and CanCan set up, but I'm trying to get into sign up page in my rails application, but its redirecting me to home page saying that I'm not authorized to access this page.
I have a custom registration controller:
class Devise::RegistrationsController < DeviseController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
def edit
#user = User.find(current_user.id)
#profile = Profile.new
end
def update
# required for settings form to submit when password is left blank
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end
end
protected
def after_update_path_for(resource)
user_path(resource)
end
private
end
It has something to do with before_filter :check_permissions,... because when I delete this line, I get an error saying
undefined method `user_registration_path'
from my registration form in my `devise/registrations#new:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
How do I fix my registration form?
Also, this is my routes:
devise_for :user, :controllers => { :registrations => "registrations" }, :skip => [:registrations, :sessions] do
get 'signup' => 'devise/registrations#new', :as => :new_user_registration
end
Okay from what it looks like you've done is used CanCans authorize! method to handle the authorization in a controller action which will raise the cancan exception error. Can you not try and do
check_authorization :unless => :devise_controller?
I back this up with a change made a cancan commit seen here adding :if and :unless options to check_authorization - closes #284. Comments can be seen in the following issue: GitHub issue 284. Where Ryan states:
It would be nice if the check_authorization method allowed a block to dynamically customize the behavior. If it returned true it would perform the authorization.
Correct me if I am wrong but is this not what you are trying to do. Hopefully this sheds some light.
Another thing with regards to your routes.rb where you have done:
devise_for :user, :controllers => { :registrations => "registrations" }, :skip => [:registrations, :sessions] do
get 'signup' => 'devise/registrations#new', :as => :new_user_registration
end
This all looks a bit mis-match to me. Do you have by any chance a devise folder containing all devise controllers in your controller directory. If so could you not try and make your devise route block look like the following:
devise_for :users, :controllers => {:sessions => 'devise/sessions', :registrations => 'devise/registrations', :passwords => 'devise/passwords'}, :skip => [:sessions] do
get '/login' => 'devise/sessions#new', :as => :new_user_session
get '/register' => 'devise/registrations#new', :as => :registrations
post '/login' => 'devise/sessions#create', :as => :user_session
get '/logout' => 'devise/sessions#destroy', :as => :destroy_user_session
end
update
From the link GitHub - CheckAuthorizationI pasted in my comment I believe you can the method check_authorization as the example shows you can do:
class ApplicationController < ActionController::Base
check_authorization
end
The controller then shows that you can:
Supply the name of a controller method to be called. The authorization check only takes place if this returns false.
check_authorization :unless => :devise_controller?

Rails 3: Devise overriding sign_up controller woes

Referenced the online documents for Devise but my override is still not working. Any one got any suggestions why not? It just goes to the root after sign in. Sign up works though.
Routes:
root :to => 'pages#index'
get "pages/index"
devise_for :users, :path => 'accounts', :controllers => { :registrations => "registrations" }
match 'profile' => 'profiles#show', :as => 'current_profile'
match 'profile/edit' => 'profiles#edit', :as => 'edit_current_profile'
put 'profile' => 'profiles#update'
resources :users do
resources :profiles
end
Registration Controller:
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
edit_current_profile_path
end
def after_sign_in_path_for(resource)
current_profile_path
end
end
def after_sign_in_path_for(resource)
current_profile_path
end
This goes in the application_controller, not the override class.

Resources