在 Rails 中限制对单个记录的授权而不是整个控制器操作

Restricting authorization to individual records instead of whole controller action in Rails

我有一个 Rails 应用程序,其中包含属于类别的文章

class Article < ApplicationRecord
  belongs_to :category


class Category < ApplicationRecord
  has_many :articles, dependent: :destroy

它有一个基本的用户模型,其中包含一些您自己的身份验证和授权,但是我 运行 遇到了一个障碍,试图限制某些用户访问某个类别下的文章

有 "admin" 个用户和 "internal" 个用户。

还有一个名为内部的类别

我想将类别设置为“内部”的任何文章的访问权限限制为仅管理员和内部用户。

如果普通用户或未登录用户尝试访问“内部”类别下的文章,他们将被重定向到主页,并且会有一条闪现消息通知他们访问被拒绝。

我不希望他们看到的特定页面是类别设置为内部的任何文章的显示页面和内部类别的显示页面。

内部类别的显示页面遍历所有类别设置为内部的文章。

我已经使用 before_action.

将其设置为限制对新页面、编辑页面和销毁页面的未授权访问
before_action :admin_user,       only: [:new, :edit, :destroy]

def admin_user
      redirect_to(root_url) && flash[:danger] = "You are not authorized!" unless current_user.admin?
    end

我的主要问题是是否有更细粒度的方法来限制对模型中单个记录的访问,而不仅仅是整个控制器操作?

我研究了一些像 cancancan 这样的精华,但它们似乎都专注于限制对整个控制器操作的访问,而不是对单个记录的访问。

如有任何建议,我们将不胜感激。

我最终想出了一种方法来完成这项工作,但我确信我的代码很丑陋,并且愿意接受清理它并使其更优雅的建议。我想我会 post 我的回答,以防它在未来对任何人有帮助。

我最后在文章控制器上添加了一个 before_action 来检查用户试图查看的文章,如果它的类别设置为 "Internal" 它只允许他们查看它,如果他们是内部用户。它还限制他们编辑它,除非他们是内部的。

用户模型有一个用于将用户设置为内部用户的布尔值。

before_action :internal_article,  only: [:show, :edit]

def internal_article
  @article = Article.find(params[:id])
  if @article.category.name == "Internal"
    redirect_to(root_url) && flash[:danger] = "You are not authorized to view that article!" unless logged_in? && current_user.internal?
  end
end 

您可以将此 class 方法放入文章模型中

def self.non_internal
  where(category: Category.where.not(name: 'internal'))
end

控制器中的一个这样使用它

@article = Article.non_internal.find(params[:id])
if @article.nil?
  redirect_to(root_url) && flash[:danger] = "You are not authorized to view that article!" unless logged_in? && current_user.internal?
end