In routes i have the root-path pointing "home#index" but when i try to override that with after_sign_up_path_for keeps redirecting me to the root path when I sign in or sign up. I have tried to put it in both in devise subclassed controller and application_controller, but it didn't work. What do I need to do here?
Application controller
class ApplicationController < ActionController::Base
protect_from_forgery
def after_sign_up_path_for(resource)
show_cities_path(resource)
end
end
registration controller
class RegistrationsController < ApplicationController
def after_sign_up_path_for(resource)
show_cities_path(resource)
end
end
routes
root :to => "home#index"
If you also have the Confirmable module enabled, you have to override after_inactive_sign_up_path_for since a new sign-up is "inactive" until it's confirmed. after_sign_up_path_for doesn't seem to get called when Confirmable is active.
Although I am late to the game, I just ran into this problem and had trouble finding the solution.
If you are using your own RegistrationsController to customize Devise, then you need to add the after_sign_up_path_for(resource) method to that controller instead of ApplicationController.
In registrations_controller.rb:
private
def after_sign_up_path_for(resource)
new_page_path
end
https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb
I struggled with this problem until realizing I had forgotten to declare that I was overriding devise's registrations controller. In my case, I'm using devise with the :user resource, so I added this to routes.rb:
devise_for :users, :controllers => {:registrations => "registrations"}
After that, the redirect that I specified in after_inactive_sign_up_path_for worked.
Override devise registrations controller has a more complete discussion on this topic, with alternative ways of declaring overrides.
Have you checked your show_cities_path exists, by executing rake routes? Might be worth having a look at https://github.com/plataformatec/devise/wiki/How-To:-Change-the-redirect-path-after-destroying-a-session-i.e.-signing-out
Actually, we can view the source code of devise to solve the problem and it's easy.
devise-3.4.1 $ vim app/controllers/devise/registrations_controller.rb
# POST /resource
def create
build_resource(sign_up_params)
resource_saved = resource.save
yield resource if block_given?
if resource_saved
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
#validatable = devise_mapping.validatable?
if #validatable
#minimum_password_length = resource_class.password_length.min
end
respond_with resource
end
end
As code show:
if resource.active_for_authentication?
...
respond_with resource, location: after_sign_up_path_for(resource)
else
...
respond_with resource, location: after_inactive_sign_up_path_for(resource)
I've just blown about 2 hours on this, but LiveReload was my issue. I was being redirected successfully but LiveReload was picking up the change on development.sqllite and overriding the request.
If using OmniAuth custom callback controllers with Rails 5.2:
In my particular case, the after sign up path was not working: but I was using OmniAuth with a custom callback controller, which was invoking the after_sign_in_path_for rather than the former:
def google_oauth2
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
# Here's the guilty line your honour:
sign_in_and_redirect #user, event: :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, kind: "Google") if is_navigational_format?
else
session["devise.google_oauth2_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
........And the sign_in_and_redirect path redirects to the after_sign_in_path_for method. So I generated a new devise controller for sessions and simply overrode that method. problem solved!
Related
By default with devise. After a user registers it automatically signs them in after sign up. Is there anyway to register a user and not auto sign them in and redirect to the login page?
You need to override Devise::RegistrationsController#create. You can see how registration works here
First, create a custom controller subclass of Devise::RegistrationsController
class RegistrationController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
respond_with resource, location: root_path # Change this to whatever route your want
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
end
Then tell devise to use custom controller:
devise_for :users, :controllers => {:registrations => "registrations"}
Assuming User is the model of course.
Experimenting with Devise 3.0 for Rails 4 and thinking about integrating into an existing app to replace my own Authentication system.
My own users_controller communicated with an API (Stripe) during registration and I'm not sure how I would include this functionality if I were to use Devise?
Am I suppose to override/extend the Devise Controller in some way? Any help would be much appreciated.
For future googlers: it is possible to call super in an action of inherited controller with block and do whatever you want, without overwriting Devise code:
class Users::RegistrationsController < Devise::RegistrationsController
def create
super do |user|
NotificationMailer.user_created(user).deliver
end
end
end
You can define the actions in the your controller and call super inside it, which will include the functionality of the corresponding devise action. And you can also add your own functionality into it.
Eg: Consider the Registrations controller (Registrations Controller)
Here, you can use the devise's create action code of Registration Controller in you own create action of Registration Controller and add your functionality as commented in the code.
class RegistrationsController < Devise::RegistrationsController
.
.
.
def create
build_resource(sign_up_params)
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
# Here the user successfully signs up, so you can use your stripe API calls here.
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
end
I have a Rails application that uses Devise for user authentication. If a user registers using the registration form, but he happens to use an existing valid username/password, instead of giving an error, I want to just log in the user. But I can't figure out how to do that.
Any suggestions?
You will need to override the devise RegistrationsController create action. After the regular registration code, you will need to add your code to check if a user already exists and sign in if the email/pass combination match. Something like this (based on the devise version you are using - this is based on the source of 2.2.4)
class RegistrationsController < Devise::RegistrationsController
def create
build_resource
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
# Add code to check if user exists and sign in
# I am just pasting in the sign_in code here and you will need to customize it as per your needs
# You can directly use params and User model, or try an keep your code generic
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
end
And add the controller to your routes as well:
devise_for :users, :controllers => { :registrations => "registrations"}
User model has one user_profile.
I just installed devise and its working fine.
I made registrations_controller.rb and it has 'create', 'after_update_path_for(resource)
', and 'edit' actions.
If I want to make it input '45' to nested column of user_profile as default value, how can I code in registration controller???
Should I make another action called 'save/or new?' , and write this?
#user.user_profile.language_id = '45'
I was making some tests, and I suggest you to use callbacks, but you can also override the actions of the RegistrationsController of Devise. I followed this thread: Override devise registrations controller and the code of the controller https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb (see that I use sign_in instead of sign_up - I'm working with Rails 3.2.8)
And this is the code with the edits for the case:
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
build_resource
resource.build_user_profile
resource.user_profile.language_id = 45
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
def update
super
end
end
And as the answer of the post said, I leave the routes as follows:
devise_for :users, :controllers => {:registrations => "registrations"}
I used a has_one relationship.
I'm trying to redirect users that have failed the sign up form (e.g. they entered a username that is already taken, they left a field blank, etc...)
I have custom failure set up for users that fail the sign in form, code below:
class CustomFailure < Devise::FailureApp
def redirect_url
root_path
end
def respond
if http_auth?
http_auth
else
redirect
end
end
However, I've been stuck on how to set this up for sign up failure. Ideally I would just like to redirect them back/to root_path, any ideas? Thank you!
You will probably need to subclass Devise::RegistrationsController and override the create action. Just copy over the create method from here and modify the redirect on failure to save.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
# modify logic to redirect to root url
end
end
Change your routes to tell Devise to use your controller:
# config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
It's a bit tedious to modify certain parts of devise to suit your needs and I suspect it's because the gem does a good job to cover most common cases. However, edge-cases for use of devise are a lot and your question points to one of them. I had to do something similar, that is, make sure devise redirects to a specific page when a user does one of the following:
submits form on an empty form
submits an already existing email.
Below is how I handled it.
First, create a controller called RegistrationsController that inherits from Devise::RegistrationsController like so:
class RegistrationsController < Devise::RegistrationsController
end
Inside this controller you will have override the create method in devise. Go to the devise github page here, https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb to view the create method and copy the code in that method. Then create a private method to override the returning statment of the last block of the if statement. Your controller should look like so,
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
response_to_sign_up_failure resource
end
end
private
def response_to_sign_up_failure(resource)
if resource.email == "" && resource.password == nil
redirect_to root_path, alert: "Please fill in the form"
elsif User.pluck(:email).include? resource.email
redirect_to root_path, alert: "email already exists"
end
end
end
It should work.
Tip:
To keep flash error messages add this line before the redirect_to in your override
resource.errors.full_messages.each {|x| flash[x] = x}
So in your registrations_controller.rb :
def create
build_resource(sign_up_params)
if resource.save
yield resource if block_given?
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
resource.errors.full_messages.each {|x| flash[x] = x} # Rails 4 simple way
redirect_to root_path
end
end
In config/routes.rb:
devise_scope :user do
get '/users', to: 'devise/registrations#new'
end