1

Ruby beginner over here. I'm currently working on a project where Users can create public and private wikis. There are three different roles: Admin, Standard User and Premium User. A Standard user can only see public wikis.

Authorization is working properly via Pundit, I've successfully been able to list the wikis I want each user to have access to, but I'm missing one thing: Wikis to which the Standard user has been added as a collaborator.

Collaborator is not a role, so I'm having difficulty adding those wikis to the index (Wiki has many users through collaborators).

If you have any ideas on how I can implement this, or perhaps an alternative route, I'd be happy to hear them.

Currently, a standard user can access only public wikis and wikis he or she has created (which are public by default). Currently, the Standard user can view and edit a private wiki he or she has been added to but only by visiting the direct wiki url.

This is what my code looks like so far:

wiki.rb

class Wiki < ActiveRecord::Base
  belongs_to :user
  has_many :collaborators
  has_many :users, through: :collaborators

  scope :visible_to, -> (user) { user && (user.premium? || user.admin?) ? all : where(public: true)  }
  scope :publicly_visible, -> {where(public: true)}
end

wiki_policy.rb

class WikiPolicy < ApplicationPolicy
  def index?
    true
  end

  def show?
    record.public? || user.present? && (record.user == user || user.admin? || user.premium? || record.users.include?(user))
  end

  def create?
    user.present? 
  end

  def new?
    create?
  end

  def update?
    user.present? && (record.user == user || user.admin? || record.users.include?(user))
  end

  def destroy?
    update?
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      if @user.present?
        wikis = Wiki.visible_to(@user)
      else
        wikis = Wiki.publicly_visible
      end
    end
  end
end

wikis_controller.rb

class WikisController < ApplicationController
  def index
    @wikis = policy_scope(Wiki).paginate(page: params[:page], per_page: 10)
    authorize @wikis 
  end
...
end
LizGee
  • 45
  • 8

2 Answers2

0

Hello fellow bloc student!

Try adding this to your policy scope:

def resolve
  if @user.present?
    wikis = Wiki.visible_to(@user)
    Wiki.all.each do |wiki|
        if wiki.users.include?(@user)
            wikis << wiki
        end
    end
    wikis
  else
    wikis = Wiki.publicly_visible
  end
end

Also, I noticed that you premium users are allowed to see ALL private wikis, not just their own.

Happy coding!

Michael Do
  • 21
  • 2
0

Thanks Michael!

Originally, I had a problem where will_paginate was not working after trying to build the array of wikis via the scope. That's why we went a different route and used the visible_to, etc scopes in the Wiki Model.

However, while trying to fix this, I found a way to keep our array the way the checkpoint intended and also to paginate them.

My policy now looks like this:

class WikiPolicy < ApplicationPolicy
  def index?
    true
  end

  def show?
    record.public? || user.present? && (record.user == user || user.admin? || user.premium? || record.users.include?(user))
  end

  def create?
    user.present? 
  end

  def new?
    create?
  end

  def update?
    user.present? && (record.user == user || user.admin? || record.users.include?(user))
  end

  def destroy?
    update?
  end

  class Scope
   attr_reader :user, :scope

   def initialize(user, scope)
     @user = user
     @scope = scope
   end

   def resolve
     wikis = []
     if user.present?
      if user.admin?
       wikis = scope.all 
     elsif user.premium?
       all_wikis = scope.all
       all_wikis.each do |wiki|
         if wiki.public? || wiki.user == user || wiki.users.include?(user)
           wikis << wiki
         end
       end
     else 
       all_wikis = scope.all
       wikis = []
       all_wikis.each do |wiki|
         if wiki.public? || wiki.users.include?(user)
           wikis << wiki 
         end
       end
     end
    end
     wikis
   end
 end
end

wiki.rb

class Wiki < ActiveRecord::Base
  belongs_to :user
  has_many :collaborators
  has_many :users, through: :collaborators
end

I was able to paginate and show the correct list of wikis (including collab wikis) by adding the following file in config/initializers

array_paginate.rb

require 'will_paginate/array'

LizGee
  • 45
  • 8