未初始化的常量 Home——由 CanCanCan 为非数据库支持的资源抛出

uninitialized constant Home -- thrown by CanCanCan for non-db backed resource

我正在使用 CanCanCan 进行授权。基本上我想要发生的是未登录用户可以访问 Home#Index,但他们需要登录才能访问 Home#Dashboard

我有这条路线:

get 'dashboard', to: 'home#dashboard', as: :dashboard

这是我的 HomeController:

class HomeController < ApplicationController
  authorize_resource except: [:index]
  skip_authorization_check only: [:index]
  layout 'marketing', only: [:index]

  def index
  end

  def dashboard
  end
end

这是我的 application_controller.rb:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_action :configure_permitted_parameters, if: :devise_controller?
  check_authorization :unless => :devise_controller?

  rescue_from CanCan::AccessDenied do |exception|
    respond_to do |format|
      format.json { head :forbidden }
      format.html { redirect_back(fallback_location: root_path, flash: { danger: exception.message }) }
    end
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:accept_invitation, keys: [:first_name, :last_name, :phone])
  end
end

但是,当我转到 /dashboard 时,这是我得到的错误:

NameError - uninitialized constant Home:
  activesupport (5.0.0.1) lib/active_support/dependencies.rb:550:in `load_missing_constant'
  activesupport (5.0.0.1) lib/active_support/dependencies.rb:203:in `const_missing'
  activesupport (5.0.0.1) lib/active_support/inflector/methods.rb:268:in `block in constantize'
  activesupport (5.0.0.1) lib/active_support/inflector/methods.rb:266:in `constantize'
  activesupport (5.0.0.1) lib/active_support/core_ext/string/inflections.rb:66:in `constantize'

可能是什么原因造成的?

编辑 1

经过一些调试,我现在意识到这似乎与我 authorizing 的操作不受 ActiveRecord 资源支持这一事实有关。

换句话说,一旦我将 :dashboard 添加到 exception 列表中,就像这样:

  authorize_resource except: [:index, :dashboard]
  skip_authorization_check only: [:index, :dashboard]

有效。页面加载非常顺利。

所以我想真正的问题是,如何 authorize/lock 关闭不是 ActiveRecord 模型的资源?

问题似乎源于我尝试 authorize_resource 获取不是 ActiveRecord 模型支持的资源的资源。

所以我不得不从控制器的开头删除 authorize_resource,然后 authorize! 每个单独的操作。然后我不得不将该规则添加到 ability.rb.

现在我的 HomeController 看起来像这样:

class HomeController < ApplicationController
  skip_authorization_check only: [:index]
  layout 'marketing', only: [:index]


  def index
  end

  def dashboard
    authorize! :read, :dashboard
  end
end

然后,在我的 ability.rb 中,我有这个:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)

    can :manage, User, id: user.id
    can :read, :dashboard if user.has_any_role? :admin, :coach, :player
  end
end

我必须在数据库中的所有 roles 中进行硬编码。

我真正想做的只是检查用户当前是否登录,但由于 w/e 原因,所有 user_signed_in? 检查都失败了。

理想情况下,我喜欢做类似的事情:

can :read, :dashboard if current_user?

或者:

can :read, :dashboard if user.user_signed_in?

但是这两个都不起作用,并给了我以下错误的变体:

undefined local variable or method `current_user' for #<Ability:0x007faca14db2c8>

或者:

undefined method `user_signed_in?' for #<User:0x007fac86b2a9c8>

如果您对我如何实现这一点有任何建议,请发表评论或写一个新答案,我会接受。在那之前,我想这将不得不做:(

我在关于 managing Non-Restful Controllers 的 CanCanCan wiki 中找到了这种方法的基础。