I have a Rails app with articles that belong to categories
class Article < ApplicationRecord
belongs_to :category
class Category < ApplicationRecord
has_many :articles, dependent: :destroy
It has a basic User model with some roll your own authentication and authorization however I am running into a road block trying to restrict certain users to the articles under a certain category
There are "admin" users and "internal" users.
There is a category called Internal as well
I want to limit the access to any article where the category is set to Internal to only admin and internal users.
If ordinary or non-logged in users try to access articles under the Internal category they will get redirected to the home page and there will be a flash message letting them know access is denied.
The specific pages I don't want them to see are the show page for any article with its category set to internal and the show page for the Internal category.
The show page for the internal category iterates through all articles with their category set to Internal.
I already have it set up to restrict unauthorized access to the new, edit and destroy pages using a before_action.
before_action :admin_user, only: [:new, :edit, :destroy]
def admin_user
redirect_to(root_url) && flash[:danger] = "You are not authorized!" unless current_user.admin?
end
My main question would be is there a more fine grained way to limit access to individual records from the model instead of just the whole controller action?
I dug into a few gems like cancancan but they all seem to be focused on limiting access to the whole controller action and not to individual records.
Any suggestions would be greatly appreciated.
I ended up figuring out a way to get this done however I'm sure my code is ugly and would be open to suggestions to clean it up and make it more elegant. I figured I would post my answer in case it ever helps anyone in the future.
I ended up adding a before_action on the articles controller that checks the article the user is trying to view and if it has it's category set to "Internal" it only lets them view it if they are an internal user. It also restricts them from editing it unless they are internal.
The user model has a Boolean to set a user to internal.
before_action :internal_article, only: [:show, :edit]
def internal_article
@article = Article.find(params[:id])
if @article.category.name == "Internal"
redirect_to(root_url) && flash[:danger] = "You are not authorized to view that article!" unless logged_in? && current_user.internal?
end
end