为具有admin属性的用户设计定义routes和before_filter

时间:2016-08-28 07:18:39

标签: ruby-on-rails ruby devise

我有一个小应用程序,我实现了设计。我添加了Devise的模型是consultant而不是user

class Consultant < ApplicationRecord
  devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :confirmable

  def admin?
    self.admin == true
  end

end

我还添加了一个属性,例如建议here选项2来识别管理员用户。

我的目标是实现只有管理顾问可以随处访问。非管理员的顾问只能访问resources :tasksget '/tasks/consultants/:id/worked', to: 'tasks#worked'。访客应该被重定向到sign_in。

为此,我在before_filter中添加ApplicationController,就像这样

class ApplicationController < ActionController::Base

  before_filter :authenticate_admin!
  skip_before_filter :authenticate_admin!, only: [:tasks]

  private
  def authenticate_admin!
    current_consultant.try(:admin?)
  end

end

并在tasks_controller.rb我添加了此before_filter

class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]

  before_filter :authenticate_consultant!

  ...

我的routes.rb定义如下

Rails.application.routes.draw do

  devise_for :consultants
  devise_scope :consultant do
    authenticated :consultant do
      root 'tasks#index'
    end

    root to: "devise/sessions#new"
  end

  get '/home', to: 'static_pages#home'
  get '/help', to: 'static_pages#help'

  get   '/tasks/consultants/:id/worked', to: 'tasks#worked'

  resources :tasks
  resources :consultants

end

我不明白为什么不验证用户,任何用户都可以随时访问

更新1

只是一个小注释,我更改before_filter的每个before_action因为before_filter已被弃用

@Raffael建议我将application_controller.rb更新为

class ApplicationController < ActionController::Base

  before_action :authenticate_admin!

  def authenticate_admin!
    unless current_consultant.try(:admin?)
      flash[:error] = 'Shoo, this is not for you'
      redirect_to root_path
    end
  end

end

但是我收到了错误

  

localhost重定向了你太多次了。

我认为这种情况正在发生,因为我正在从routes.rbapplication_controller.rb重定向。当它试图访问devise/sessions#new时需要进行认证。

我试图通过将以下内容添加到application_controller.rb

中的before_action来避免这种情况
before_action :authenticate_admin!, :except => ['devise/sessions#new']

更新2:解决方案

最后这就是我所做的,首先我创建了一个名为admin_controller.rb

的新文件
class AdminController < ApplicationController

  before_action :authenticate_admin!

  protect_from_forgery with: :null_session

  def authenticate_admin!
    unless current_consultant.try(:admin?)
      flash[:error] = 'Shoo, this is not for you'
      redirect_to root_path
    end
  end

end

对于需要管理员权限的控制器,我从新类扩展

class AnyController < AdminController

application_controller.rb

class ApplicationController < ActionController::Base

  before_action :authenticate_consultant!, :except => ['devise/sessions#new']

  protect_from_forgery with: :null_session

end

并在routes.rb

Rails.application.routes.draw do

  devise_for :consultants

  root to: 'tasks#index'
...

不是一个优雅的解决方案,但它的工作原理。例如,将所有管理控制器放在自己的命名空间中会更好。

1 个答案:

答案 0 :(得分:1)

从过滤器链中返回一个falsey值不会再停止过滤器链(它在以前的Rails版本中也是如此)。

如果您希望before_filter阻止执行控制器操作,则需要重定向或呈现。

例如:

def authenticate_admin!
  unless current_consultant.try(:admin?)
    flash[:error] = 'Shoo, this is not for you'
    redirect_to root_path
  end
end

或:

def authenticate_admin!
  unless current_consultant.try(:admin?)
    flash[:error] = 'You need to be logged in as an admin to use this resource'
    render 'login_dialog'
  end
end