Multiple devise user type root routes - ruby-on-rails

I have just set up my STI structure with a Devise User model. I have two user types (business and lender) and would like them to be sent to separate root paths after signing in. My models look like this:
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :type
end
lender.rb
Class Lender < User
end
business.rb
Class Business < User
end
My routes file looks like:
Lendingloop::Application.routes.draw do
# User route
devise_for :users, skip: [:registrations]
# Lending routes
devise_for :lenders, skip: :sessions
authenticated :lender do
root :to => "LenderAccount#dashboard", :as => "lender_authenticated_root"
end
#Business routes
devise_for :businesses, skip: :sessions
authenticated :business do
root :to => "BusinessAccount#dashboard", :as => "business_authenticated_root"
end
# Error Routes
get "/404", to: 'errors#not_found'
get "/422", to: 'errors#unacceptable'
get "/500", to: 'errors#internal_error'
# Root route
root :to => 'StaticPages#landing'
end
As you can see I have an authenticated do block which I would like to redirect lenders and businesses to their specific root pages. I have a LenderAccount and BusinessAccount controller setup with dashboard actions in them and corresponding views.
When I log in as a lender or a business, I'm redirected to my root_path which is 'StaticPages#landing'. That should only be for non-logged in users.
Update
I went through the devise documentation and added the following to my application_controller.rb file:
def after_sign_in_path_for(user)
if user.type == "Business"
business_authenticated_root_path
elsif user.type == "Lender"
lender_authenticated_root_path
else
root_path
end
end
I am also seeing a strange error in my console when I attempt to go to the dashboard page directly from lender_authenticated_root_path:
Rendered /Users/questifer/.rvm/gems/ruby-1.9.2-p320#rails3tutorial/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.7ms)
[2014-04-22 12:31:31] ERROR Errno::ECONNRESET: Connection reset by peer
/Users/bvlaar/.rvm/rubies/ruby-1.9.2-p320/lib/ruby/1.9.1/webrick/httpserver.rb:56:in `eof?'
/Users/bvlaar/.rvm/rubies/ruby-1.9.2-p320/lib/ruby/1.9.1/webrick/httpserver.rb:56:in `run'
/Users/bvlaar/.rvm/rubies/ruby-1.9.2-p320/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'
Does anyone have an idea as to how I can get these authenticated blocks to handle the proper root redirects?

I got the roots working by changing my routes.rb file to:
routes.rb
root :to => 'business_account#dashboard', :constraints => lambda { |request| request.env['warden'].user.class.name == 'Business' }, :as => "business_root"
root :to => 'lender_account#dashboard', :constraints => lambda { |request| request.env['warden'].user.class.name == 'Lender' }, :as => "lender_root"
Now my two user types can login to their accounts and be directed to their respective controllers and dashboards.

I think I can help. I had a similar problem. In my routes.rb file I created a "home" screen for non-logged in users.
Rails.application.routes.draw do
root "home#index"
devise_for :users
resources :home
resources :dashboard
The home_controller.rb looks like this:
class HomeController < ApplicationController
def index
if user_signed_in?
redirect_to :controller=>'dashboard', :action =>'index'
end
end
end
dashboard_controller.rb looks like this, and is only for logged in users:
class DashboardController < ApplicationController
before_filter :authenticate_user!
def index
end
end
The views for each (home.html.erb & dashboard.html.erb) can then reflect content for visitors or logged in users.
I used this tutorial to sort it out. I don't know if it's overkill or not, this is my first application, but ti seems to be what you are asking for.
http://www.tonylea.com/2012/rails-authentication-with-devise/
Hope that helps.

Related

How to Remove/Disable Sign Up From Devise

I'm trying to remove/disable the user/sign_up path from Devise. I'm doing this because I don't want random people gaining access to the application. I have it partly working by adding the following in routes.rb
Rails.application.routes.draw do
devise_scope :user do
get "/sign_in" => "devise/sessions#new" # custom path to login/sign_in
get "/sign_up" => "devise/registrations#new", as: "new_user_registration" # custom path to sign_up/registration
end
...
devise_for :users, :skip => :registration
end
However, this breaks <%= link_to "Profile", edit_user_registration_path, class: "btn btn-info btn-flat" %>
which I want to keep so that users can update their profile.
I know it's because of the devise_for :users, :skip => :registration
Is there a solution for this issue?
Running
Devise (4.2.0, 4.1.1, 4.1.0)
Rails 4.2.5
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
The easiest way is just removing :registerable devise module from the default list defined into your Model (the class name used for the application’s users, usually User).
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
...
end
So you'll have it like this:
class User < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
...
end
Solution to removing sign_up path from Devise
Enter the following at the beginning of routes.rb
Rails.application.routes.draw do
devise_scope :user do
get "/sign_in" => "devise/sessions#new" # custom path to login/sign_in
get "/sign_up" => "devise/registrations#new", as: "new_user_registration" # custom path to sign_up/registration
end
...After the statement above, add the following below in routes.rb
devise_for :users, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
This will remove/disable the user/sign_up path for Devise without breaking edit_user_registration_path
Restart your rails server and it should work.
I just had the same issue. My solution is a mix of these answers.
Comment out or remove :registerable in user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, #:registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Remove the registration paths from devise_for in routes.rb:
devise_for :users, :skip => [:registrations], controllers: {
sessions: 'users/sessions'
}
Now Devise will skip all of the registration links from their view and also you no longer have the registration paths on your routes.
Redirecting from controller
I solved this issue by redirecting /sign_up to /sign_in from the controller, while preserving the functionality of editing user info. For instance:
In controllers/users/registrations_controller.rb
# GET /resource/sign_up
def new
redirect_to new_user_session_path and return
super
end
In routes.rb, I pointed registrations resource to this controller:
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
So whenever users visit route /sign_up, it'll redirect them to /sign_in. Just remember to use and return after the redirection to prevent multiple render/redirect
Since as is just an alias for devise_scope, you can put all that in just one block.
devise_for :users, skip: [:registrations]
as :user do
get "/sign_in" => "devise/sessions#new" # custom path to login/sign_in
get "/sign_up" => "devise/registrations#new", as: "new_user_registration" # custom path to sign_up/registration
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
Below code seem to do the trick for me:
Rails.application.routes.draw do
devise_scope :users do #notice "users" here, not "user"
get "/sign_in" => "devise/sessions#new" # custom path to login/sign_in
get "/sign_up" => "devise/registrations#new", as: "new_user_registration" # custom path to sign_up/registration
end
devise_for :users, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
...

Devise - undefined local variable or method `current_member'

I am using members as the Devise model. I have placed before_action :authenticate_member! in the application controller.
But when i try to use the following in the views
<%= current_member.inspect %>
Am getting the following error
undefined local variable or method `current_member' for #<#<Class:0x007fe48ad32130>:0x007fe48e389af8>
#<Class:0x007fe48ad32130>#_app_views_brands_members_index_html_erb___144793605481589474_70309807670200
app/views/brands/members/index.html.erb, line 1
<%= current_member.inspect %>
<%= link_to('Logout', destroy_brands_member_session_path, :method => :delete) %>
Member Model - app/model/member.rb
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
acts_as_paranoid
# Associations
belongs_to :company
accepts_nested_attributes_for :company
end
Devise Initialiser
config.default_scope = :member
Controller
class Brand::ApplicationController < ApplicationController
before_action :authenticate_member!
private
end
Members Controller brands/members_controller.rb
class Brands::MembersController < Brand::ApplicationController
def index
end
end
ROUTEs
Rails.application.routes.draw do
# devise_for :members
# Brands Routes
constraints :subdomain => "brands" do
scope :module => "brands", :as => "brands" do
# namespace :brands do
# devise_for :members
devise_for :members, controllers: {
sessions: 'brands/members/sessions',
registrations: 'brands/members/registrations',
confirmations: 'brands/members/confirmations',
passwords: 'brands/members/passwords'
}
get '/members' => 'members#index'
end
end
# API Routes
constraints :subdomain => "api" do
scope :module => "api", :as => "api" do
api_version(
module: "V1",
header: { name: "Accept", value: "application/vnd.skreem+json; version=1" },
defaults: { format: :json }
) do
# devise_for :members
# resources :products
end
end
end
end

Devise Current User Can't Get Nested Data to Show in View

I'm trying to make an example app to learn about namespace/scopes/modules
Normally I would user current_user helper but I have Client::Addresses nested in behind and would like to grab say the user's city and just display it on their edit page (devise registration/edit screen)
<%= current_user.?? %>
Using the line below. I also added inverse_of as my understanding it'll reverse the relationship as well but no avail.
<%= #user.addresses.cacity %>
I think this is pretty close #user.id works but adding the rest error reads. Looks like I also dealt with strong params just not sure. I'm doing this to practice namespacing:scopes/modules:
undefined method `cacity' for #<ActiveRecord::Associations::CollectionProxy []>
It would be great to do something like.
<%= current_user.addresses.cacity %>
Here's some additional information with what I got so far, let me know if additional info is needed.
routes.rb
Rails.application.routes.draw do
namespace :client do
resources :subscriptions
end
# Security Devise Setup
devise_for :admins
devise_for :users
# Main Pages
root 'website/page#index'
# Client Sections
resources :users do
scope module: "client" do
root :to => 'dashboard#index'
resources :addresses
end
end
namespace :admin do
root :to => 'panel#index'
end
end
user.rb
class User < ActiveRecord::Base
include Gravtastic
gravtastic
# Devise Settings
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
# Model Relationships
has_many :addresses, :inverse_of => :user, class_name: 'Client::Address'
end
client/address.rb
class Client::Address < ActiveRecord::Base
belongs_to :user, :inverse_of => :addresses
end
#user.addresses
is a collection, and you send a (instance) method cacity to a collection, which, as errors states, do not respond to it.
#user.addresses.first.cacity would work.
You could limit the relation to has_one:
has_one :address #...
Which will allow you to use the following:
#user.address.cacity

rails devise - how to have 2 devise authentications for two different user models?

We have admin_users and we have regular users and they both have separate tables, models and devise logins.
It might make more sense to use devise against just one user table and use cancan for the roles but the application has already been created with two separate user tables and it's not an option to change them at this point.
The admin users functionality, including login, is working ok.
Initially standard users access was only through a link and token based authentication but that needs to change.
In routes we had
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users
resources :users, :only => [:update, :edit]
So I added the root path for the users resource as indcated by the Devise documentation as the place where a successful login goes to:
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users
resources :users, :only => [:update, :edit] do
root to: "practitioner_activities#welcome"
end
and I then also tried removing the only => e.g.
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users
resources :users do
root to: "practitioner_activities#welcome"
end
For the (regular) User model I changed:
devise :token_authenticatable,
to also have:
devise :token_authenticatable, # token login still permitted.
:database_authenticatable, :recoverable, :rememberable,
:trackable, :validatable
# Not sure if these will make a difference but they are like this in other apps.
but instead of redirecting to practitioner_activities#welcome the users gets sent back to the login screen.
I notice that the first line in the console that is logged for the login POST is using the AdminUser model, not the User model. Any idea how to fix?
Started POST "/" for 127.0.0.1 at 2012-08-23 13:54:50 -0400
Processing by HelpController#show as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"28iGxAB+URoIKoBQtPizGAosJoZ/V7Vko1w/bYMvesE=", "new_user_session_path"=>{"email"=>"Borger.Cathy#meridianschools.o
rg", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign In"}
AdminUser Load (0.4ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = 1 LIMIT 1
The login form itself is:
= semantic_form_for(:new_user_session_path,
:html => {:id => "session_new"}) do|f|
= f.inputs do
= f.input :email, :label => "Username"
= f.input :password
= f.input :remember_me, :as => :boolean, :if => false
= f.commit_button "Sign In"
In the end the main things was to just the devise generators again and then edit the devise views.

Rails: Using Devise with single table inheritance

I am having a problem getting Devise to work the way I'd like with single table inheritance.
I have two different types of account organised as follows:
class Account < ActiveRecord::Base
devise :database_authenticatable, :registerable
end
class User < Account
end
class Company < Account
end
I have the following routes:
devise_for :account, :user, :company
Users register at /user/sign_up and companies register at /company/sign_up. All users log in using a single form at /account/sign_in (Account is the parent class).
However, logging in via this form only seems to authenticate them for the Account scope. Subsequent requests to actions such as /user/edit or /company/edit direct the user to the login screen for the corresponding scope.
How can I get Devise to recognise the account 'type' and authenticate them for the relevant scope?
Any suggestions much appreciated.
There is an easy way to handle STI in the routes.
Let's say you have the following STI models:
def Account < ActiveRecord::Base
# put the devise stuff here
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
def User < Account
end
def Company < Account
A method that is often overlooked is that you can specify a block in the authenticated method in your routes.rb file:
## config/routes.rb
devise_for :accounts, :skip => :registrations
devise_for :users, :companies, :skip => :sessions
# routes for all users
authenticated :account do
end
# routes only for users
authenticated :user, lambda {|u| u.type == "User"} do
end
# routes only for companies
authenticated :user, lambda {|u| u.type == "Company"} do
end
To get the various helper methods like "current_user" and "authenticate_user!" ("current_account" and "authenticate_account!" are already defined) without having to define a separate method for each (which quickly becomes unmaintainable as more user types are added), you can define dynamic helper methods in your ApplicationController:
## controllers/application_controller.rb
def ApplicationController < ActionController::Base
%w(User Company).each do |k|
define_method "current_#{k.underscore}" do
current_account if current_account.is_a?(k.constantize)
end
define_method "authenticate_#{k.underscore}!" do
|opts={}| send("current_#{k.underscore}") || not_authorized
end
end
end
This is how I solved the rails devise STI problem.
I just ran into the exact scenario (with class names changed) as outlined in the question. Here's my solution (Devise 2.2.3, Rails 3.2.13):
in config/routes.rb:
devise_for :accounts, :controllers => { :sessions => 'sessions' }, :skip => :registrations
devise_for :users, :companies, :skip => :sessions
in app/controllers/sessions_controller.rb:
class SessionsController < Devise::SessionsController
def create
rtn = super
sign_in(resource.type.underscore, resource.type.constantize.send(:find, resource.id)) unless resource.type.nil?
rtn
end
end
Note: since your Accounts class will still be :registerable the default links in views/devise/shared/_links.erb will try to be emitted, but new_registration_path(Accounts) won't work (we :skip it in the route drawing) and cause an error. You'll have to generate the devise views and manually remove it.
Hat-tip to https://groups.google.com/forum/?fromgroups=#!topic/plataformatec-devise/s4Gg3BjhG0E for pointing me in the right direction.
try to change routes like so:
devise_for :accounts, :users, :companies
because Devise uses plural names for it's resources
Please let me know if it help you
I don't think this is possible without overriding the sessions controller. Each sign_in page has a specific scope that devise will authenticate against as defined by your routes.
It may be possible to use the same sign_in page for multiple user scopes by using the devise_scope function in your routes file to force both :users and :companies to use the same sign in page (a how-to can be found here), but I'm pretty certain that you would have to modify your sessions controller to do some custom logic in order to determine which type of user is signing in.

Resources