authenticate_user!
(which you haven't shown/explained to us, but is probably a method from devise
or similar?) is presumably to do with signing in -- that's authentication, not authorization, and is therefore outside the scope of what Pundit
tries to solve.
Authentication is all about checking "are you signed in?". If this check fails, then the server responds with a 401 status.
Authorization is about checking "are you allowed to perform this action (potentially as a guest)?". If this check fails, then the server responds with a 403 status
Now presumably, you have also added some code like this in your application:
class ApplicationController < ActionController::Base
include Pundit
after_action :verify_authorized, except: :index # !!!!!
end
This after_action
check is a safety net; it's there to ensure that you never forget to authorize an endpoint -- as that would allow the action to be performable by any user, by default! The presence of this check is what's causing your error above.
So. With that explained, let's look how you can implement this.
- Should
RecipesController#show
be accessible by guests, or only by logged-in users?
If, and only if, the answer is "guests" then add this:
skip_before_action :authenticate_user!, only: :show
- Assuming you've already performed any necessary authentication, you want to let any user see any
recipe
. How can you implement that?
Option 1 (recommended):
class RecipePolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end ## WARNING!! NOTICE THAT THE `Scope` CLASS ENDS HERE!!!
def show?
true # !!!!
end
end
class RecipesController < ApplicationController
# ...
def show
@recipe = Recipe.find(params[:id])
authorize(@recipe) # !!!
# ...
end
end
Option 2 (also works, but worse practice as it means you can't rely on unit tests for the policy class):
class RecipesController < ApplicationController
def show
skip_authorization # !!!
@recipe = Recipe.find(params[:id])
# ...
end
end