11

How do I serialize permissions with active_model_serializers? I don't have access to current_user or the can? method in models and serializers.

Jo Liss
  • 30,333
  • 19
  • 121
  • 170

3 Answers3

23

First, to get access to the current_user in the serializer context, use the new scope feature:

class ApplicationController < ActionController::Base
  ...
  serialization_scope :current_user
end

In case you are instantiating serializers manually, be sure to pass the scope:

model.active_model_serializer.new(model, scope: serialization_scope)

Then inside the serializer, add custom methods to add your own authorization pseudo-attributes, using scope (the current user) to determine permissions.

If you are using CanCan, you can instantiate your Ability class to access the can? method:

attributes :can_update, :can_delete

def can_update
  # `scope` is current_user
  Ability.new(scope).can?(:update, object)
end

def can_delete
  Ability.new(scope).can?(:delete, object)
end
Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • I don't understand -- did you answer your own question right away? – Jesse Wolgamott Jul 26 '12 at 01:51
  • 2
    Yes, I did – see [this article](http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/). I wanted this piece of knowledge preserved, but found it too trivial/specialized to post on my blog, so I posted it here, Q&A style. – Jo Liss Jul 26 '12 at 09:05
  • 1
    @JoLiss As an alternative to the "super.merge" style, you can say `attributes :can_update, :can_delete` and then define can_update and can_delete as methods in the serializer. Either works, though. – tee Jul 27 '12 at 04:59
  • You can also delegate the `can?` method to your model for even better readability — see http://stackoverflow.com/a/3293522/797639. – pierrea Oct 16 '14 at 10:21
3

We created a gem that provides this functionality: https://github.com/GroupTalent/active_model_serializers-cancan

ghempton
  • 7,777
  • 7
  • 48
  • 53
2

I think you can pass anything you want to serialization_scope so I simply pass the Ability.

class ApplicationController < ActionController::Base
 ...
 serialization_scope :current_ability

 def current_ability
   @current_ability ||= Ability.new(current_user)
 end

end


class CommentSerializer < ActiveModel::Serializer
  attributes :id, :content, :created_at, :can_update

  def can_update
    scope.can?(:update, object)
  end

end

I can't do otherwise since my abilities are actually based on two variables (not in the example above).
If you still need access to current_user you can simply set an instance variable on Ability.

Romain
  • 21
  • 1
  • 1