Overriding devise registration controller for redirect - ruby-on-rails

Devise functionality needs to be customized and the the RegistrationsController is created.
However, the default set-up for the create action is
super do |resource|
end
which in itself is a bit of a black box, as it goes to the superclass. It obvious is wired up for redirection. Thus:
super do |resource|
[...]
if #user.save?
redirect_to some_user_attribute_path
else
redirect_to a_parameter_based_path
end
end
is not possible as it will naturally create a
AbstractController::DoubleRenderError in Users::RegistrationsController#create
Devise wikis only deal with successful actions or all-encompassing approaches.
It is a goal to avoid ApplicationController methods, as this use-case has very specific behaviours for only user creation according success or failure (in practice the return is to the same page, but in the case of the failure, is defined via a params[:company][:id] value in lieu of #user.company_id
How can this be achieved?

I think you should override the method completely since you don't want the redirection handling that is after the yield. So, you could do this:
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
if resource.save?
redirect_to some_user_attribute_path
else
redirect_to a_parameter_based_path
end
end
end
Note: If you need to sign up the user or any other stuff that devise does, you should copy it from the original method

Related

RoR: Devise enum roles, redirect after sign in based on role?

I have a user model with two roles as enums
enum role: [:'Standard', :'Admin']
I am trying to redirect based on the user role to relevant page after sign-in with Devise, I have used the recommended way of doing it on the docs.
In my sesssions controller...
def create
super
sign_out :user
end
def after_sign_in_path_for(_resource)
if resource.role == "Standard"
redirect_to dashboards_path
else
redirect_to dashboards_admin_index_path
end
end
And in my controller...
before_action :authenticate_salesperson!
before_action :set_project, only: %i[show edit update destroy]
I get this error saying too many renders/redirects (highlights super in create method) when logging in and i'm wondering why?
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return"
How to work around this? Ty.
Would be nice if you paste the whole controllers, but it seems like the after_sign_in_path_for method gets called before each time you visit either page, which creates a loop and hence the error. You can easily verify this by logging some text in each of the if else methods to double check.
What you should do is to add this logic to the controller, which is the root path like so
class DashboardController < ApplicationController
before_action: :after_sign_in_path_for, only: :index
private
def after_sign_in_path_for
if current_user.standard?
redirect_to dashboards_path
else
redirect_to dashboards_admin_index_path
end
end
end
Thanks. This works after I removed the "redirect_to's" in the "after_sign_in" method in my sessions controller
def after_sign_in_path_for(_resource)
if current_salesperson.standard?
dashboards_path
elsif current_salesperson.admin?
dashboards_admin_index_path
end
end
And in my user model...
def admin?
role == "Admin"
end
def standard?
role == "Standard"
end
You are redirecting too many times in the same action, this is why the message: "Render and/or redirect were called multiple times in this action."
Just return the path, delete redirect sentence! You only can redirect once in every action method!
Greetings

Devise after_confirmation_path_for and nil redirection error

In Ruby on Rails 4, one of my actions fails because it redirects to nil. What is the best practice to get a list of redirections and find the faulty call ?
Edit:
The offending code is:
class ConfirmationsController < Devise::ConfirmationsController
def after_confirmation_path_for(resource_name, resource)
redirect_to some_specific_path_helper
end
end
Whenever I hit the email confirmation action in Devise, this action fails and reports about a nil redirection.
So my mistake was that after_confirmation_path_for is not an action but a simple path helper. Therefore, calling redirect from within confirmation_path_for is improper and causes this method to return nil (i.e. nothing).
The proper use of after_confirmation_path_for is to have it returning the chosen path, like so:
class ConfirmationsController < Devise::ConfirmationsController
def after_confirmation_path_for(resource_name, resource)
# just return the path, do not call redirect
some_specific_path_helper
end
end

Don't allow sign in after sign up in devise

I am using devise for authentication, devise automatically sign in after signing up,
i need just sign up but not sign in.
There is similar question link but it didn't help me
Disclaimer: The following code is not verified in my practice. Just in theory they are likely to work.
At first you need to use your custom RegistrationsController. You can check how to do that in Devise wiki.
After setting up, things are fairly easy. Do the following in your custom controller
class Users::RegistrationsController < Devise::RegistrationsController
def create
super #Nothing special here.
end
protected
def sign_up(resource_name, resource)
true
end
end
How does it work? In Devise's code, #create will call a protected method #sign_up after saving successfully. This method does nothing but sign in the user. What we need to do is to overwrite this method to stop that action. Of course you can even add more of your logic here if necessary.

Redirect Devise before_filter :authenticate_user to sign in path

I'm using devise and have a quick question. How can I redirect the :authenticate_user! before_filter to the user sign up page instead of sign in? I've been going through https://github.com/plataformatec/devise/blob/master/lib/devise/controllers/helpers.rb but haven't had much luck figuring out a solution.
I had a similar issue where I needed to redirect to the signup if the user was not logged in.
I fixed it by adding a method to the application_controller.rb and using it as a before filter in the other controllers.
Keep in mind that is is more of a temporary solution because it skips a bunch of deviseĀ“s abstractions.
before_filter :auth_user
def auth_user
redirect_to new_user_registration_url unless user_signed_in?
end
You're going to have to create a custom FailureApp that inherits from Devise's FailureApp as seen here: https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-when-the-user-can-not-be-authenticated
I added a wiki page showing the correct way to do this with a failure app (as Steven initially hinted at):
Redirect to new registration (sign up) path if unauthenticated
The key is to override the route method, like so:
# app/lib/my_failure_app.rb
class MyFailureApp < Devise::FailureApp
def route(scope)
:new_user_registration_url
end
end
and then have Devise use your failure app:
# config/initializers/devise.rb
config.warden do |manager|
manager.failure_app = MyFailureApp
end
This approach is preferable to overriding authenticate_user! in your controller because it won't clobber a lot of "behind the scenes" stuff Devise does, such as storing the attempted URL so the user can be redirected after successful sign in.
With multiple user types
If you have Admin and User Devise resources, you'll probably want to keep the default "new session" functionality for admins. You can do so quite easily by checking what type of scope is being processed:
# app/lib/my_failure_app.rb
class MyFailureApp < Devise::FailureApp
def route(scope)
scope.to_sym == :user ? :new_user_registration_url : super
end
end

Custom Devise controller

I would like to customize my registrations controller for Devise in Rails. I understand that you must create a controller like this:
class AccountsController < Devise::SessionsController
def create
super
end
end
Well, that's all very good. But then let's say I want to fully control what happens in my #create action. How do I do that? How do I manually create a model and pass it all the params? Would Account.create(params[:account]) handle it smoothly? Is there some internal stuff going on I should know about or is my only option to call #super inside the action?
As long as you fulfil your required fields you can call Account.create in your example, I'm pretty sure the default Devise required fields are login, password and password_confirmation
We do this in a CRUD screen for creating devise users,
#admin = Admin.new(params[:admin])
if #admin.save
redirect_to admin_admins_path, :notice => 'New Administrator has been added'
else
render :action => "new"
end
and you don't want to extend the Devise session controller, a normal controller extending ApplicationController is fine or you can extend Devise::RegistrationsController and overwrite the methods you want to tweak in a registrations_controller.rb file
You can also have a look at the source on Github, if you want to be sure you're overriding things properly, and be sure you're not missing any processing...
https://github.com/plataformatec/devise/tree/master/app/controllers

Resources