我正在尝试创建一个用于学习 Ruby On Rails 的迷你博客。
我使用 Devise-token-auth gem 进行身份验证,使用 Pundit gem 进行权限。我使用资源方法分层组织项目
当我尝试删除帖子时,没有任何反应。更新工作正常......
当我尝试调试时,错误 NoMethodError: undefined method `destroy' for nil:NilClass 当我将代码行 authorize Posts::Destroy.new(@post).execute 放在控制台时出现
我研究了很多但找不到解决方案,你能帮我吗?
这些是我的代码
class Posts::Destroy
attr_accessor :post
def initialize(post)
@post = post
end
def execute
post.destroy
end
end
class PostsController < ApplicationController
before_action :set_post, only: %i[show update destroy]
before_action :authenticate_user!, except: :index
def index
posts = Posts::List.new(params).execute
render json: posts, meta: pagination(posts), each_serializer: PostSerializer, status: :ok
end
def show
render json: @post, serializer: PostSerializer, list_comments: true, status: :ok
end
def create
@post = authorize Posts::Create.new(post_params).execute
render json: @post, serializer: PostSerializer, status: :created
end
def update
authorize @post
Posts::Update.new(post_params, @post).execute
render json: @post, serializer: PostSerializer, status: :ok
end
def destroy
authorize Posts::Destroy.new(@post).execute
format.json { head :no_content }
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
authorize @post = Post.find(params[:id])
end
# Only allow a list of trusted parameters through.
def post_params
params.require(:post).permit(:title, :description, :category_id, :user_id)
end
end
class PostPolicy < ApplicationPolicy
def new?
user_is_owner_of_record?
end
def index?
true
end
def show?
true
end
def create?
user.present? && (user&.admin || user_is_owner_of_record?)
end
def update?
user.present? && (user&.admin || user_is_owner_of_record?)
end
def destroy?
user.present? && (user&.admin || user_is_owner_of_record?)
end
def user_is_owner_of_record?
@user == @record.user
end
end
class ApplicationController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
include ErrorsHandler::Handler
include ActionController::MimeResponds
include ActionController::Serialization
include Pundit::Authorization
protect_from_forgery with: :null_session
prepend_before_action :configure_permitted_parameters, if: :devise_controller?
after_action :verify_authorized, except: :index, unless: :devise_controller?
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
around_action :switch_locale
private
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
def default_url_options
{ locale: I18n.locale }
end
def user_not_authorized
flash[:alert] = 'You are not authorized to perform this action.'
redirect_back(fallback_location: root_path)
end
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update, keys: %i[name username])
devise_parameter_sanitizer.permit(:sing_up, keys: %i[password email name username])
end
def pagination(object)
{
current_page: object.current_page,
per_page: object.per_page(params),
total_pages: object.total_pages,
total_count: object.total_count
}
end
end
我相信是时候授权当前用户没有被传递
我只检查了controller里面有没有set_post,不知道还要测试什么
希望能正常删帖
欢迎来到SO!
def destroy
authorize Posts::Destroy.new(@post).execute
format.json { head :no_content }
end
authorize
正在尝试根据 Posts::Destroy.new(@post).execute
返回的内容采取行动
def execute
post.destroy
end
那么返回的是什么? 根据文档
#delete
:
删除数据库中的记录并冻结此实例以反映不应进行任何更改(因为它们无法持久化)。
所以它返回一个内存中的
post
实例,但是你不能在它上面调用任何依赖数据库的方法,因为它只存在于内存中。
def destroy?
user.present? && (user&.admin || user_is_owner_of_record?)
end
def user_is_owner_of_record?
@user == @record.user
end
这就是我们发现问题的地方:
@record.user
是一个数据库调用,它试图查找关联的 user
记录。但是@record
已经不存在于数据库中,所以调用失败。
你有两个选择:
authorize
在你之前#destroy
: def destroy
authorize @post
Posts::Destroy.new(@post).execute
format.json { head :no_content }
end
#user_is_owner_of_record?
调用中删除数据库调用: def destroy?
user.present? && (user&.admin || user_is_owner_of_record?)
end
def user_is_owner_of_record?
@user.id == @record.user_id
end