0

The problem in testing a create action is that the object is not already created. Thus a class policy initialisation could state:

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

with @shop = @promotion.shop_id added to the edit/update/delete policy actions.

However, the user may have a role within that shop that allows it to do some privileged actions, such as create ...

def shopmanager 
  @roleshopuser ||= Roleshopuser.where(['user_id = ? AND shop_id = ? AND role_id IN (?)', user.id, @shop, [1,2]]).first
end

note: this functions properly on edit/update/destroy actions, thus validating the testing fixtures

As the initialisation process indicates, the promotion requires a shop_id and is thus a submitted param to the create action. Therefore the controller action is defined as (with the puts confirming the presence of the parameter):

def create
  puts params[:promotion][:shop_id]
  @target_shop = params[:promotion][:shop_id]
  @promotion = Promotion.new(promotion_params)
  authorize @promotion

and the policy adapted accordingly

  def create?
    @shop = @target_shop
puts user.id
puts user.admin?
puts shopmanager.nil?
    !user.nil? && (user.admin? || !shopmanager.nil?)
  end

again the puts do indicate that there is proper handling of the attributes and method

The test however fails

  test "should create promotion" do
    @shop = shops(:three_4)
    @shopusers.each do |user|
      sign_in user
      @shopusers.each do |user|
        sign_in user
        assert_difference('Promotion.count') do
post promotions_url, params: { promotion: { name: (@promotion.name + user.id.to_s), shop_id: @promotion.shop_id [...]
        end
  
        assert_redirected_to promotion_url(Promotion.last)
      end
      sign_out user
    end
  end

From the puts data, the policy runs on user.admin?, but the policy fails where true is returned for the next user fixture when running method shopmanager.nil? (admin is false). As the edit/update functions work with the same fixtures, this points to an error in the policy for create.

What is it?

Jerome
  • 5,583
  • 3
  • 33
  • 76

1 Answers1

0

There is a path through this as indicated in documentation.

For the above case, the initialization requires modification to handle additional elements

  attr_reader :user, :promotion, :shop

  def initialize(context, promotion)
    @user = context.user
    @shop = context.shop
    @promotion = promotion
  end

the Class-specific controller needs amending to pass on the context, adjusted for whether the object already exists or not.

class PromotionsController < ApplicationController
  include Pundit
  private
  
    def pundit_user
      if @promotion.blank?
        shop = params[:promotion][:shop_id]
      else
        shop = @promotion.shop_id
      end
      CurrentContext.new(current_user, shop)
    end

Then the policy can check if the user is a manager of the shop.

Jerome
  • 5,583
  • 3
  • 33
  • 76