Temporary disabling of registrations in Devise - ruby-on-rails

I am using Devise in my Rails 5 project and I would like to temporarily disable new user registrations. I know I can remove the view's link, or edit the routes file to accomplish this, but that requires a change to code with a new deployment. I would like to add an option in my administrative console to disable the ability for new users to register for a period of time.
I have this functionality enabled, but it's a hacky work around. When I disable the ability for people to register, all I am currently doing is hiding the 'new user registration' link in the devise view. Anyone who knows the default paths can work around this.
How can I change this functionality at runtime?

Follow This Link for overriding the Registration Controllers for Devise.
Basically you need to override Devise default Registeration controller and put up a before filter for new & create action which checks if admin allows to create new users if not then redirect to root_path or whatever path you want.
Alter the devise_for line in config/routes.rb to override the registration controller:
devise_for :users, controllers: { registrations: "registrations"}
app/controllers/registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController
before_action :check_new_registration_allowed?, only: [:new, :create]
protected
def check_new_registration_allowed?
redirect_to root_path unless ##allow_new_registration
end
end
Please be noted that I used ##allow_new_registration global variable to check if new registration is allowed. You can turn this on/off after admin action. Alternatively it would be good if you store these information in DB and query it.

Related

Rails 5 Devise multi-user landing pages / custom profiles

I'm not sure if I'm searching for the answer using the wrong terms, but I can't find a good solution to what I'm trying to do, it can't be that unique of a scenario, but I'm a bit of a noob so I apologize if I missed something somewhere.
Rails 5 project using Devise to handle 3 users for a 2-sided marketplace (very close to taskrabbit, ect) : admin, clients, and hosts. Clients build requests, hosts bid on the requests.
When a client logs in I'd like to redirect them to a landing page that has all their current/past requests (and as a consequence the bids, etc). The same for hosts with their bids.
When an admin logs in I want to build an admin panel that lets the admin view all users/hosts.
I'm utterly confused as to how to organize the controllers/views so that clients/hosts can have their own landing page without messing up the index view for when admins log in and would (I think?) use the same clients/index view to get a list of all the users.
Any help would be greatly appreciated. Thanks!
You could redirect from within the Index controller if the logged-in user is an admin, somewhat like:
if current_user.admin?
redirect_to :admin_view
end
If the three user roles mentioned have totally different properties and meta-data, then create three different devise models and different "home-page" actions for each one of them. Redirect to their respective homepage by overriding the after_sign_in_path_for devise action. As an example, you may create a new folder named "admins" in the controllers folder and create a new file called "registrations_controller.rb"
class Admins::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_in_path_for(resource)
custom_home_page_path
end
end
Repeat the above step for Clients and Hosts as well.
Update 'devise_for' lines in "routes.rb" as follows:
devise_for :admins, controllers: { registrations: 'admins/registrations'}
devise_for :clients, controllers: { registrations: 'clients/registrations'}
devise_for :hosts, controllers: { registrations: 'hosts/registrations'}
However, if you have one universal devise model (say User) and under that you have a column specifying the role, then perform the changes as given below.
In controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_in_path_for(resource)
if current_user.admin?
admin_home_page_path
elsif current_user.client?
client_home_page_path
else
hosts_home_page_path
end
end
end
and in routes.rb
devise_for :users, controllers: { registrations: 'admins/registrations'}

How to have root view when user is not logged in rails?

I am building a rails app and I use Devise for authentication. I want to show a product first page when user comes to www.mydomain.com instead of www.mydomain.com/users/sign_in which is devise default!
I will also want to show a different root view when user is logged in. This feels like a very common use case, is there a easy way to do this? Is this there in documentation or can anyone help me with this?
You can use the authenticated route helper provided by Devise to add a constraint on the routes so that they are only available to logged in users:
Rails.application.routes.draw do
devise_for :users
authenticated :user do
root 'secret#index', as: :authenticated_root
end
root "home#index"
end
The advantage over #Sergio Tulentsev's answer is that this does not cause a redirect or require any additional logic in the controller.
However the reason your app is redirecting to /users/sign_in is most likely that you are using before_action :authenticate_user! in your ApplicationController so that the controller handling the root path is requiring authentication and redirecting to the sign in. You can fix this (while retaining a secure by default setup) by skipping the callback:
class HomeController < ApplicationController
skip_before_action :authenticate_user!
# ...
end
This applies to any controller that should not require authentication. You can skip specific actions by using the only and except options. Just remember that whitelists are more secure than blacklists.
I'd do this way, have a single route for root path:
# routes.rb
root to: 'home#index'
Then check for current user and decide which page to show.
class HomeController < ApplicationController
def index
if current_user
redirect_to some_page_path
# or render some content directly in this response
render :some_view
else # no logged-in user
# same, render or redirect
end
end
end

How to create an action where would be a form for sign in/up with Devise?

I am building a mobile version of our website and I would need to create a different views for sign up/in for mobile users. These two actions should be in a different controller.
My problem is that I don't know how to prepare instances for sign up/in for Devise in a different controller(s)...
How to make that?
Thanks
You mean you want to implement sign up/in in your own controller?
If so, you can modify routes.rb first
devise_for :users, :controllers => { :sessions => "controllername" }
And modify the controllername_controller.rb
class ControllernameController < Devise::SessionsController
def create
# your implementation
end
def destroy
# your implementation
end
end

Using a different layout file for devise login

I want to use a different layout file for logging into devise.
I've tried a static page but I get the error undefined local variable or method 'resource'.
Currently, in my application controller I have:
layout :layout_by_resource
protected
def layout_by_resource
if devise_controller?
"signin"
else
"application"
end
end
The problem with this is that every devise view uses the layout file 'login', which isn't good because I currently use devise's edit registration form for a account page.
Anybody know the best way to use a different layout file for signing into devise?
You might need to do two things to make this work.
1) Create seperate controllers inheriting from the Devise controllers, with your stated layout call. Instructions
2) To customize the views themselves further even copy over the views. Instructions Might not be nescessary.
Regarding 1) Controller(s): If you just want to customize login, you'd need to target the sessions controller.
# app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
layout :layout_for_action
protected
def layout_for_action
if params[:action] == '...' # See what the action is called internally beforehand
"signin"
else
"application"
end
end
end
You then need to instruct Devise to use your controller in config/routes.rb:
devise_for :admins, :controllers => { :sessions => "sessions" }
You can run this command
rails generate devise:views
This will generate devise views files for you to customize your layout.

Devise/Rails - How to allow only admin to create account for others?

I am using devise as my authentication solution and now i am thinking about authorization. In my project I (the admin) is the only person authorized to create account for others.
I wonder if there is a way to do it without to much hack. In fact, Devise doesn't allow user to access to the signup page if he is already logged in.
Thanks for your advice on it!
Setting :skip => :registrations also kills the ability for a user to edit their user info. If that's not what you are after you can instead create a (minimal) custom registrations controller and only remove the new_user_registration_path while preserving the edit_user_registration_path.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
# If you're not using CanCan, raise some other exception, or redirect as you please
raise CanCan::AccessDenied
end
end
# routes.rb
devise_for :users, :controllers => { :registrations => "registrations" }
Once you do this you also need to move the directory views/devise/registrations to just views/registrations.
You can try the rails_admin gem in conjunction with Devise to handle any admin-specific tasks. You'll need to add more code to set it up, but at least you avoid hacking around the solution in terms of changing your interactions with Devise.
It actually looks like in the later versions of Devise you can just remove the "registerable" declaration from your model and it will take care of this for you.

Resources