0

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
Tyler
  • 3
  • 3

1 Answers1

1

params is not available in the wiki_policy.rb because it isn't passed in the authorize method. authorize passes the record (so the Wiki object that was found) and the current_user object. You can skip finding the current wiki again. Also, in this method and others that are actions (update?, edit?, etc.) you need to return either true or false. So, you need to determine whether or not the user is an admin, collaborator or the owner, according to your specifications.

def show?
  record.user_id == user.id or Wiki.where(id: Collaboration.where(:user_id => user.id).pluck(:wiki_id)).include?(record) or user.role?(:admin)
end

That will give you a true or false return and check all of the three items you were requiring for authorization. If you want to alter it, you could use if/else statements, just make sure that you return true or return false on all possibilities.

nikkon226
  • 998
  • 6
  • 11