goodjobbin85
goodjobbin85

Reputation: 111

Ruby on Rails: destroy function not deleting item

I have a user and article model where a user can have many models, and have restricted the delete function to user or admin. yet when i attempt to destroy the article, i get the following error:

undefined method `user' for nil:NilClass

and its pointing to this private function in my articles controller:

def require_same_user
    if current_user != @article.user and !current_user.admin?
        flash[:danger] = "You can only edit or delete your own articles"
        redirect_to root_path
    end
end

this is my whole controller file:

class ArticlesController < ApplicationController
before_action :set_article, only: [:edit, :update, :show]
before_action :require_user, except: [:index, :show]
before_action :require_same_user, only: [:edit, :update, :destroy]

def index 
    @articles = Article.paginate(page: params[:page], per_page: 5)
end

def show 

end

def new
    @article = Article.new
end

def edit 

end

def update
    @article.update(article_params)
    if @article.save
        flash[:success] = "Article successfully updated!"
        redirect_to article_path(@article)
    else
        flash[:danger] = "Sorry, try again..."
        render :edit
    end
end

def create 
    @article = Article.new(article_params)
    @article.user = current_user
    if @article.save
        flash[:success] = "New article created"
        redirect_to articles_path
    else
        flash[:danger] = "Sorry, invalid values"
        render :new
    end
end

def destroy
    @article = Article.find(params[:id])
    @article.destroy
    flash[:success] = "Article deleted"
    redirect_to articles_path
end

private

def article_params
    params.require(:article).permit(:name, :title, :description)
end

def set_article
    @article = Article.find(params[:id])
end

def require_same_user
    if current_user != @article.user and !current_user.admin?
        flash[:danger] = "You can only edit or delete your own articles"
        redirect_to root_path
    end
end

end

the articles and users exist in db so what could this be? thanks in advance

Upvotes: 2

Views: 643

Answers (2)

Make sure set_article runs before destroy action.

In your controller:

before_action :set_article, only: [:edit, :update, :show, :destroy]

Upvotes: 1

Sebasti&#225;n Palma
Sebasti&#225;n Palma

Reputation: 33471

You're setting the article using the set_article function, but in the case of the require_same_user function, it doesn't know what's the value of @article; so in that case, the value is nil, as it's not in the scope, nor figure as an instance variable created before.

def require_same_user
  # Here there's no @article, so it's evaluated as nil,
  # and nil doesn't have a method user.
  if current_user != @article.user ... 
    ...

One approach could be to set the set_article also to be executed before the require_same_user does it.

before_action :set_article, only: %i[edit update show require_same_user]

You could also divide your code in smaller pieces to be used back again whenever you need it:

def require_same_user
  redirect_to_root_path unless article_owner? && admin?
end

def redirect_to_root_path
  flash[:danger] = 'You can only edit or delete your own articles'
  redirect_to root_path
end

def admin?
  current_user.admin?
end

def article_owner?
  current_user == @article.user
end

Upvotes: 2

Related Questions