他の誰かがこれに対する解決策を探している場合、ここで私がしたことです。gem Pundit を追加し、"link_#{rel}" というメソッドを追加して、リンクのシリアル化 (および通常の承認) を担当する Policy クラスを作成しました。次のような基本シリアライザーを作成しました。
module Api
class BaseSerializer < ActiveModel::Serializer
include Pundit
def self.link(rel, &block)
unless block_given?
Rails.logger.warn "Link without block (rel '#{rel}'), no authorization check"
return super
end
method = "link_#{rel}"
# We need to let the super class handle the evaluation since
# we don't have the object here in the class method. This block
# will be evalutated with instance_eval in the adapter (which has
# the object to be serialized)
super do
policy_class = PolicyFinder.new(object).policy
unless policy_class
Rails.logger.warn "Could not find policy class for #{object.class}."
next
end
user = scope
policy = policy_class.new(user, object)
unless policy.respond_to?(method)
Rails.logger.warn "Serialization of #{object.class} infers link with rel '#{rel}'. " \
"But no method '#{method}' in #{policy.class}."
next
end
next unless policy.public_send(method)
instance_eval(&block)
end
end
end
end
次に、次のような他のシリアライザーが BaseSerializer から継承します。
module Api
class UserSerializer < BaseSerializer
type 'user'
attributes :name,
:email,
:followers_count,
:following_count,
:created_at,
:updated_at
link :self do
api_user_url(object)
end
link :edit do
api_user_url(object)
end
link :follow do
follow_api_user_url(object)
end
link :unfollow do
unfollow_api_user_url(object)
end
end
end
したがって、ポリシーは通常の Pundit ポリシーと同様に、シリアル化する必要がある (またはシリアル化しない) リンクごとにいくつかのメソッドが追加されています。
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def link_self
true
end
end
module Api
class UserPolicy < ApplicationPolicy
alias current_user user
alias user record
def link_edit
current_user && current_user.id == user.id
end
# show follow link if user is not current_user and
# current_user is not already following user
def link_follow
current_user && current_user.id != user.id && !current_user.following?(user)
end
# show follow link if user is not current_user and
# current_user is following user
def link_unfollow
current_user && current_user.id != user.id && current_user.following?(user)
end
end
end