0

First off, I'm very new to Ruby and Ruby on Rails having only worked with them for a few days. I'm currently trying to redirect the page a user lands on after signing in to a specific page based on their role and I'm not quite sure how to do it. Does anyone know how I might approach this? I've used the following links but can't get them to work.

I'm using Devise for authentication and Rolify for my roles.

This is my routes.rb file:

    Rails.application.routes.draw do
    mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
    devise_for :admins
    devise_for :users, path_names: {sign_in: "login", sign_out: "logout"}
    devise_scope :user do
      authenticated :user do
        root :to => 'pages#videolibrary'
      end

  unauthenticated :user do
    root :to => 'devise/registrations#new', as: :unauthenticated_root
  end
end

I've made a Passthrough controller but I don't know how to link the controller so that it's used. Or even if this is the right way to approach this.

Here's the passthroughcontroller.rb:

class PassthroughController < ApplicationController
  def index
    if current_user.has_role? :admin
      redirect_to 'pages#videolibrary'
    elsif current_user.has_role? :retail
      redirect_to 'pages#retail'
    elsif current_user.has_role? :commercial
      redirect_to 'pages#commercial'
    elsif current_user.has_role? :business
      redirect_to 'pages#business'
    elsif current_user.has_role? :manager
      redirect_to 'pages#videolibrary'
    else
      redirect_to 'devise/registrations#new'
    end
  end
end

I've tried following these posts but have can't get it to work:

Devise Redirects to specific page based on User Role on Login

How can I redirect a user's home (root) path based on their role using Devise?

how to change the rails root url based on the current user or role

Whit this link I don't have a role_constraint.rb file in my lib directory.

Maybe someone here has an idea on how to approach this?

EDIT:

I've updated my application controller to now read:

class ApplicationController < ActionController::Base
      # Prevent CSRF attacks by raising an exception.
      # For APIs, you may want to use :null_session instead.
      protect_from_forgery with: :exception

        before_action :configure_permitted_parameters, if: :devise_controller?
      protected
      def configure_permitted_parameters
        devise_parameter_sanitizer.for(:sign_up)  { |u| u.permit(  :email, :password, :password_confirmation, role: []  ) }
      end

    def after_sign_in_path_for(resource)
      # Here you can write logic based on roles to return different after sign in paths
      if current_user.has_role? :admin
        get 'pages/videolibrary' => "pages#videolibrary", as: :retail_page
      elsif current_user.has_role? :retail
        get 'pages/retail' => "pages#commercial", as: :retail_page
      elsif current_user.has_role? :commercial
        get 'pages/commercial' => "pages#commercial", as: :commercial_page
      elsif current_user.has_role? :business
        get 'pages/business' => "pages#business", as: :business_page
      elsif current_user.has_role? :manager
        get 'pages/manager' => "pages#manager", as: :manager_page
      else
        get 'devise/registrations' => "devise/registrations#new"
      end
    end
end

And this is my routes.rb:

Rails.application.routes.draw do
  mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
  devise_for :admins
devise_for :users, path_names: {sign_in: "login", sign_out: "logout"}
devise_scope :user do
  authenticated :user do
    root :to => 'pages#videolibrary'
  end
  unauthenticated :user do
    root :to => 'devise/registrations#new', as: :unauthenticated_root
  end
    get 'pages/welcome'
    get 'pages/home' => "pages#videolibrary"
    get 'videolibrary' => "pages#videolibrary"
    get 'pages/*page' => "pages#show"
    get 'pages/retail' => "pages#retail"
    get 'pages/commercial' => "pages#commercial"
    get 'pages/business' => "pages#business"
    get 'pages/manager' => "pages#manager"
  end
end

Here is my user.rb file if needed:

class User < ActiveRecord::Base
  rolify
  resourcify
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  ROLES = %w[admin retail commercial business manager]

end

And these are the revelant routes with rake routes:

                 root GET    /                               pages#videolibrary
 unauthenticated_root GET    /                               devise/registrations#new
        pages_welcome GET    /pages/welcome(.:format)        pages#welcome
           pages_home GET    /pages/home(.:format)           pages#home
         videolibrary GET    /videolibrary(.:format)         pages#videolibrary
                      GET    /pages/*page(.:format)          pages#show
          retail_page GET    /pages/retail(.:format)         pages#retail
      commercial_page GET    /pages/commercial(.:format)     pages#commercial
        business_page GET    /pages/business(.:format)       pages#business
         manager_page GET    /pages/manager(.:format)        pages#manager

I'm now getting a NoMethodError in Devise::SessionsController#create

undefined method `get' for #Devise::SessionsController:0x9879660

    get 'pages/manager' => "pages#manager", as: :manager_page
  else
    get 'devise/registrations' => "devise/registrations#new"
  end
end
Community
  • 1
  • 1
Chris Bryant
  • 3
  • 1
  • 3

1 Answers1

1

Devise has a controller method you can override called after_sign_in_path_for this is talked about in the devise docs here. (The devise wiki and especially the how to examples are really helpful)

In your application controller

def after_sign_in_path_for(resource)
  # Here you can write logic based on roles to return different after sign in paths
  if current_user.has_role? :admin
    videolibrary_path
  elsif current_user.has_role? :retail
    retail_page_path
  elsif current_user.has_role? :commercial
    commercial_page_path
  elsif current_user.has_role? :business
    business_page_path
  elsif current_user.has_role? :manager
    videolibrary_path
  else
    new_user_path
  end
end

You will need to add the routes for the pages e.g

get 'pages/retail => "pages#retail", as: :retail_page # this sets up a named link 'retail_page_path' which you can use in controllers and views

Check out the rails routing guide for more info. Also once you have written your routes you can run rake routes in the console to output all your apps routes as well as their named routes (like retail_page_path)

Subtletree
  • 3,169
  • 2
  • 18
  • 25
  • Thank you for the help! I'm now getting a new error, I've updated the post to reflect the error and pasted in relevant files (I think?). I appreciate the help, would you happen to know what's giving me an error now? – Chris Bryant Oct 29 '15 at 17:18
  • The code you have included in your controller e.g `get 'pages/videolibrary' => "pages#videolibrary", as: :retail_page` is only for the routes.rb file. That code defines a route and basically says if someone asks for www.mysite.com/pages/videolibrary point them to the videolibrary action in the pages controller. It then makes a variable (named_route) called retail_page_path that links to that url. If you remove the routes code from the controller and replace it with each corresponding named route it should hopefully work! – Subtletree Oct 30 '15 at 10:31
  • So just to clarify, in my answer above when I wrote `commercial_page_path` for example I don't mean to replace that with the commercial page path I mean keep `commercial_page_path` there as it is a named route which inserts the correct path itself. Try just copying that whole method. – Subtletree Oct 30 '15 at 10:37