I'm having some trouble implementing one last step in my pundit authorizations...I have a projects model as well as a project_policy that authorizes which users in the app can view and interact w/ the project. However, my projects have several components - one of which is an index of project versions that is accessed within the project (a project has_many versions)...so I need to be able to restrict users access to this list of versions as well... along with the default project profile (I restrict if a users is not an owner/admin or collaborator). I currently have these 'versions', however, setup in their own model.
Details: Currently if I am not an admin/owner or collaborator, the restrictions work when I try to access the url projects/20 (it will redirect me and say "you're not authorized"), but if i navigate to 'projects/20/versions' or 'projects/20/versions/1' or 'projects/20/versions/new' it does not restrict me. Do I need to create a new version_policy for this or can i just restrict this within the project_policy since technically the versions are a part of the project? & what would the code look like that I need to add?
My code is as follows - thanks in advance for any and all help...
PROJECT_POLICY.RB
class Scope < Struct.new(:user, :scope)
end
def update?
user.project_admin? or user.project_collaborator?
end
# method used in projects controller, (study pundit docs)
def visit?
if project.is_private?
user.project_admin?(project) || user.project_owner?(project) || user.project_collaborator?(project)
else
true
end
end
def main_profile?
true
end
def projectversions?
user.project_admin?(project) || user.project_owner?(project)
end
def settings?
user.project_admin?(project) || user.project_owner?(project)
end
def collaboration?
user.project_admin?(project) || user.project_owner?(project)
end
def invite_admin?
user.project_admin?(project) || user.project_owner?(project)
end
def invite_collaborator?
user.project_admin?(project) || user.project_owner?(project)
end
end
PROJECT.RB (PROJECTS MODEL)
class Project < ActiveRecord::Base
...
...
has_many :versions, dependent: :destroy
validates :title, presence: true, length: { maximum: 100 }
validates :background, presence: true
validates :user_id, presence: true
default_scope -> { order('created_at DESC') }
def user_name
owner.try(:name)
end
def user_name=(name)
self.user = User.find_by_name(name) if name.present?
end
def private?
self.is_private == true
end
def public?
self.is_private == false
end
end
PROJECTS_CONTROLLER.RB
class ProjectsController < ApplicationController
before_filter :signed_in_user, only: [:create, :new, :edit, :update]
# Creates redirect and alert when pundit sees someone is not authorized (via :not_authorized_in_project below)
rescue_from Pundit::NotAuthorizedError, :with=>:not_authorized_in_project
def new
@project = Project.new
end
def show
@project = Project.find(params[:id])
authorize @project, :visit?
@user = User.where(:id => @project.user_id).first
rescue Pundit::NotAuthorizedError
flash[:danger] = "You are not authorized to access this page."
redirect_to projects_path || root_path
end
def create
@project = current_user.own_projects.build(project_params)
if @project.save
flash[:success] = "Welcome to your new project."
redirect_to @project
else
render 'new'
end
end
def update
@project = Project.find(params[:id])
if @project.update_attributes(project_params)
flash[:success] = "Project Created"
redirect_to @project
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "Project destroyed"
redirect_to users_path
end
def projectadmins
@title = "Project Admins"
@project = Project.find(params[:id])
authorize @project, :visit?
@projects = @project.projectadmins.paginate(page: params[:page])
render 'show_projectadmin_project'
rescue Pundit::NotAuthorizedError
flash[:danger] = "You are not authorized to access this page."
redirect_to projects_path || root_path
end
def projectversions
*# If I should place the authorizations in this controller...What code should go here? And how would I also restrict the new/show actions for projects/versions i.e, 'projects/20/versions/new', etc?*
end
def settings
@project = Project.find(params[:project_id])
authorize @project
render 'settings'
end
private
def project_params
params.require(:project).permit(:title, :background, :is_private)
end
# USED FOR PUNDIT REDIRECT & ALERT FLASH WHEN SOMEONE IS NOT AUTHORIZED TO ACCESS SOMETHING
def not_authorized_in_project
flash[:danger] = "You are not authorized to access this page."
redirect_to project_path(@project) || root_path
end
end
ROUTES.RB
ProductionApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :projects do
resources :versions
match '/settings'=>'projects#settings', :via=>:get, :as=>:settings
match '/collaboration'=>'projects#collaboration', :via=>:get, :as=>:collaboration
match '/invite_admin'=>'projects#invite_admin', :via=>:patch, :as=>:invite_admin
match '/invite_collaborator'=>'projects#invite_collaborator', :via=>:patch, :as=>:invite_collaborator
get :autocomplete_user_name, :on=>:collection
end
resources :versions do
resources :users
end
resources :projects do
member do
get :projectadmins
end
end
resources :admin_relationships, only: [:create, :destroy]
resources :collaborator_relationships, only: [:create, :destroy]
# get "static_pages/home"
# get "static_pages/help"
# get "static_pages/about"
end
much appreciated...let me know if anything else I missed would be helpful to see.