I am taking a course that has me creating a basic wiki. I'm definitely new to this. I need to restrict users from simply typing in a wiki id that they want to view directly in the URL (example: wikis/5). The only people who should be able to view a wiki should be the wiki owner, an admin or a collaborator on that wiki.
I have successfully restricted the index view so that a signed in user only sees their own wiki, a public wiki or a wiki they collaborate on.
I have tried to implement similar code in my WikiPolicy, but it isn’t working and I can’t seem to find a solution. The code I have now simply will show the wiki if the user is logged in. I know my logic is good, because I can substitute a value for params[:id] like “5” and it works as expected.
wikis_controller.rb
def show
@wiki = Wiki.find(params[:id])
authorize @wiki
end
wiki_policy.rb
def show?
scope.where(:id => record.id).exists?
current_wiki = Wiki.find(params[:id])
collaborations = Collaboration.where(:user_id => user)
collab_wikis = Wiki.where(id: collaborations.pluck(:wiki_id))
collab_wikis.include?(current_wiki)
end
Here is the code that I used in my wiki_policy.rb to return a set of wikis that a particular user is authorized to view. I believe this works because it is looking at all wikis, instead of being dependent on a particular wiki that the user is trying to view.
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
wikis = []
if user.role?(:admin)
wikis = scope.all # if the user is an admin, show them all the wikis
elsif user.role?(:premium)
collaborations = Collaboration.where(:user_id => user)
collab_wikis = Wiki.where(id: collaborations.pluck(:wiki_id))
all_wikis = scope.all
all_wikis.each do |wiki|
if !wiki.is_private || wiki.user_id == user.id || collab_wikis.include?(wiki)
wikis << wiki # if the user is premium, only show them public wikis, or that private wikis they created, or private wikis they are a collaborator on
end
end
else # this is the lowly standard user
collaborations = Collaboration.where(:user_id => user)
collab_wikis = Wiki.where(id: collaborations.pluck(:wiki_id))
all_wikis = scope.all
wikis = []
all_wikis.each do |wiki|
if !wiki.is_private? || wiki.user_id == user.id || collab_wikis.include?(wiki)
wikis << wiki # only show standard users public wikis and private wikis they are a collaborator on
end
end
end
wikis # return the wikis array we've built up
end
end