Skip to content

Instantly share code, notes, and snippets.

@mewdriller
Last active December 19, 2021 01:48
Show Gist options
  • Save mewdriller/4980855 to your computer and use it in GitHub Desktop.
Save mewdriller/4980855 to your computer and use it in GitHub Desktop.
Serializing CanCan rules to JSON for use in a client-side application
class Ability
include CanCan::Ability
def initialize(user)
can :read, Comment
if user.valid?
can :create, Comment
can :manage, Comment, author_id: user.id
end
end
def as_json
abilities = []
rules.each do |rule|
abilities << { can: rule.base_behavior, actions: rule.actions.as_json, subjects: rule.subjects.map(&:to_s), conditions: rule.conditions.as_json }
end
abilities
end
end
@daino3
Copy link

daino3 commented Dec 18, 2015

Hey, just dropping a note - love this solution, but found something useful - if you use rule.instance_variable_get('@expanded_actions') it allows you to serialize all actions that are aliased. For example:

class Ability
  include CanCan::Ability

  def initialize(_user)
    alias_action :create, :read, :update, :edit, :destroy, to: :crud

    can :crud, Comment
  end

  def as_json
    # bogus call to CanCan module to set expanded_actions
    can?(:initialize, :abilities)
    rules.map do |rule|
      {
        can: rule.base_behavior,
        actions: rule.instance_variable_get('@expanded_actions'),
        subjects: rule.subjects.map(&:to_s),
        conditions: rule.conditions.as_json
      }
    end
  end
end

Will serialize all aliased actions for crud

Note:
The one "gotcha" of this approach is that you have to call can?(:initialize, :abilities) in the as_json method to initialize the expanded_actions variable for each rule. This is somewhat weird behavior, but you can't get around it because the CanCan module really kicks off with a call to can?() or cannot?(). Otherwise, expanded_variables will not be set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment