ruby on rails - Conditional links with active_model_serializers -


i'm trying create hypermedia api in rails. i'd serialize payloads active_model_serializers using json_api adapter. doesn't seem trivial serialize links conditionaly.

it's kind of blog application users can follow other users. when serialize user resource, usera, want have link rel :follow if current_user not following usera , link rel :unfollow if current_user following usera. seems extremely trivial use case when creating hypermedia api. know if there's way of doing active_model_serializers?

i wrote (and include in serializers):

def self.link(rel, &block)       serializer = self       super         user = scope         next unless serializer.can?(user, rel, @object)         instance_eval(&block)       end     end  # , in serializer (just usual):  link :self   api_user_path(object.id) end 

it work. don't feel right. , wouldn't surprised if future changes active_model_serializers screw things me.

if else looking solution here did. added gem pundit , made policy classes in charge of link serialization (as usual authorization) adding methods called "link_#{rel}". created base serializer this:

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}"       # need let super class handle evaluation since       # don't have object here in class method. block       # evalutated instance_eval in adapter (which has       # object serialized)       super         policy_class = policyfinder.new(object).policy         unless policy_class           rails.logger.warn "could not find policy class #{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 rel '#{rel}'. " \             "but no method '#{method}' in #{policy.class}."           next         end         next unless policy.public_send(method)         instance_eval(&block)       end     end    end end 

then other serializers inherit baseserializer, like:

module api   class userserializer < baseserializer     type 'user'     attributes :name,                :email,                :followers_count,                :following_count,                :created_at,                :updated_at      link :self       api_user_url(object)     end      link :edit       api_user_url(object)     end      link :follow       follow_api_user_url(object)     end      link :unfollow       unfollow_api_user_url(object)     end   end end 

so policies normal pundit policies added methods each link should serialized (or not).

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 not current_user ,     # current_user not following user     def link_follow       current_user && current_user.id != user.id && !current_user.following?(user)     end      # show follow link if user not current_user ,     # current_user following user     def link_unfollow       current_user && current_user.id != user.id && current_user.following?(user)     end   end end 

Comments

Popular posts from this blog

javascript - Thinglink image not visible until browser resize -

firebird - Error "invalid transaction handle (expecting explicit transaction start)" executing script from Delphi -

mongodb - How to keep track of users making Stripe Payments -