I'm trying to create a mini blog for learning Ruby On Rails.
I used the Devise-token-auth gem for authentication and the Pundit gem for permissions. i used resources method to organize the project in layers
When I try to delete a post nothing happens. The update is working normally...
when I tried to debug, the error NoMethodError: undefined method `destroy' for nil:NilClass appeared when I put the line of code authorize Posts::Destroy.new(@post).execute in the console
I've researched a lot but I couldn't find a solution, can you help me please?
these are my codes
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
I believe it is time to authorize that a current user is not being passed
I checked if there was a set_post in the controller only, I don't know what else to test.
I hope I can delete posts normally
authorizeis trying to act on what is being returned byPosts::Destroy.new(@post).executeSo what's being returned? According to the docs
#delete:So it returns an in-memory instance of
post, but you can't call any database-reliant methods on it because it only exists in memory.And here's where we find the problem:
@record.useris a database call that tries to look up the associateduserrecord. But@recordno longer exists in the database, so the call fails.You have two options:
authorizebefore you#destroy:#user_is_owner_of_record?call: