Search code examples
ruby-on-railspundit

Policy and case operator for the show view


I've got 3 types of users on my website :

  • visitors
  • members
  • VIP members (there is a vip attribute in User model)

Sports predictions are posted in the website but users don't have the same rights :

  • Visitors can only see past predictions
  • Members can only see predictions that are occurring in the next hour
  • VIP members can see all predictions.

I have made a PredictionPolicy to define who can see the show view of the Prediction model.

I think I need to use the case operator to list different scenario but I can't figure out how.

Here is what I started to write (which doesn't work) :

  def show?
  x = @record.start_time - Time.now
    case x
      when -1.0/0 .. 0
        User.all
      when 0 .. 3600
        user
      when -1.0/0 .. +1.0/0
        user.gold
      end
  end
    end

Do you have any idea of the solution ?

Many thanks

class PredictionPolicy < ApplicationPolicy

  def show?
  x = @record.start_time - Time.now
    case x
      when -1.0/0 .. 0
        User.all
      when 0 .. 3600
        user
      when -1.0/0 .. +1.0/0
        user.vip
      end
  end

  def create?
    user.vip
  end

  def update?
     user.team
  end

  def destroy?
    user.team
  end

  def user_feed?
    user.vip
  end

  def upvote?
    user.vip
  end

  class Scope < Scope
    def resolve
      if user
        if user.vip
          scope.all
        else
          scope.where(status: [:won, :lost, :void])
        end
        else
          scope.where(status: [:won, :lost, :void])
      end
    end

  end
end

Solution

  • You example is a fine illustration for using scopes.

    You should define subclass named Scope under your PredictionPolicy. The implementation should look something like this:

    class PredictionPolicy
    
      # In this class we define which user can
      # see which preditions.
      class Scope
        attr_reader :user, :scope
    
        def initialize(user, scope)
          @user = user
          @scope = scope
        end
    
        def resolve
          if user.blank? # guest
            scope.where('start_time < ? AND status IN (?)', Time.now, [:won, :lost, :void])
          elsif user.vip
            scope.all
          else
            scope.where('start_time < ? AND status IN (?)', Time.now + 1.hour, [:won, :lost, :void])
          end
        end
      end
    end
    

    With the policy defined, you can use it in your controller:

    def index
      @predictions = policy_scope(Prediction)
    end