Reputation: 111
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
Reputation: 561
Make sure set_article
runs before destroy
action.
In your controller:
before_action :set_article, only: [:edit, :update, :show, :destroy]
Upvotes: 1
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