如何过滤 rails 中的对象,以便只有创建它的用户或管理员才能销毁该对象?

How to filter an object in rails so that only the user that created it or an admin can destroy that object?

我有一个简单的 rails 应用程序,用户可以在其中引用(例如,“有两种事物是无限的:宇宙和人类的愚蠢;我不确定宇宙。”——阿尔伯特·爱因斯坦等)。

我希望只有创建报价的用户或管理员能够编辑和删除报价。

目前我有一个前置过滤器,它设置了创建引言的用户,如下所示:

before_action :correct_user, only: :destroy

这是我的 Quotes controller:

class QuotesController < ApplicationController
  before_action :set_artist,   only: [:show, :edit, :update, :destroy]
  before_action :logged_in_user, only: [:create, :new, :destroy, :update, :edit ]
  before_action :correct_user,   only: :destroy

  def index
    @quotes = Quote.all.paginate(page: params[:page], per_page: 12)
  end

  def show
  end

  def new
    @quote = Quote.new
  end

  def create
    @quote = current_user.quotes.build(quote_params)
    if @quote.save
      flash[:success] = "Quote created!"
      redirect_to @quote
    else
      render :new
    end
  end

  def edit
  end

  def update
    if @quote.update(quote_params)
      flash[:success] = "Quote updated"
      redirect_to @quote
    else
      render :edit
    end
  end

  def destroy
    @quote.destroy
    flash[:success] = "Quote deleted"
    redirect_back(fallback_location: browse_path)
  end

  private

    def set_artist
      @quote = Quote.find(params[:id])
    end

    def quote_params
      params.require(:quote).permit(:content, :source, :topic_id, :speaker_id)
    end

    def correct_user
      @quote = current_user.quotes.find_by(id: params[:id])
      redirect_to root_url if @quote.nil?
    end
end

在 Rails 中执行此操作的惯用正确方法是什么?我应该这样做吗:

def correct_user
  if user.admin?
    @quote = current_user.quotes.find_by(id: params[:id])
  else
   @quote = current_user.quotes.find_by(id: params[:id])
  end
  redirect_to root_url if @quote.nil?
end

是否有我缺少的更简洁或 Rails 的方法?另外,如何确保只有创建报价的用户才能删除或编辑报价?我的 correct_user 方法是否已经涵盖了?

我认为您可以检查用户是否是管理员,或者 user.id 是否与 quote.user_id 相同,在这种情况下您 return 为真,使用 || 如果两个表达式中的任何一个 return 为真,你 return 为真,所以你可以这样做:

def correct_user
  current_user.admin? || current_user.id == @quote.user_id
end

因此您可以创建一个辅助方法,在用户不是管理员或不是引号的情况下重定向 author/owner:

before_action :check_permission, only: %i[edit destroy]

def correct_user
  current_user.admin? || current_user.id == @quote.user_id
end

def check_permission
  redirect_back(fallback_location: browse_path) unless correct_user
end

如果这两个表达式中的某些表达式被评估为真,您可以使用前回调检查编辑和销毁以及任何其他。

我会在操作前设置两个。

before_action :resource, only: [:edit, :update, :destroy]
before_action :allow_admin, only: [:edit, :update, :destroy]

首先会找到引用资源

def resource
  @quote = current_user.quotes.find_by(id: params[:id])
end

其他将允许管理员访问资源

def allow_admin
  if current_user.admin? && @quote.nil?
    @quote = Quote.find_by(id: params[:id])
    # Search all quotes, as admin has access to all
  elsif @quote.nil?
    redirect_to root_url
  end
end