Class: ApiMaker::AbilitiesLoader

Inherits:
ApplicationService show all
Defined in:
app/services/api_maker/abilities_loader.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationService

#api_maker_json

Constructor Details

#initialize(abilities:, ability:, serializers:) ⇒ AbilitiesLoader

Returns a new instance of AbilitiesLoader.



4
5
6
7
8
9
10
11
12
# File 'app/services/api_maker/abilities_loader.rb', line 4

def initialize(abilities:, ability:, serializers:)
  @ability = ability
  @abilities = abilities.map(&:to_sym)
  @abilities_data = {}
  @abilities_with_no_conditions = []
  @abilities_with_no_rules = []
  @groupings = {}
  @serializers = serializers
end

Instance Attribute Details

#abilitiesObject (readonly)

Returns the value of attribute abilities.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def abilities
  @abilities
end

#abilities_dataObject (readonly)

Returns the value of attribute abilities_data.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def abilities_data
  @abilities_data
end

#abilities_with_no_conditionsObject (readonly)

Returns the value of attribute abilities_with_no_conditions.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def abilities_with_no_conditions
  @abilities_with_no_conditions
end

#abilities_with_no_rulesObject (readonly)

Returns the value of attribute abilities_with_no_rules.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def abilities_with_no_rules
  @abilities_with_no_rules
end

#abilityObject (readonly)

Returns the value of attribute ability.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def ability
  @ability
end

#groupingsObject (readonly)

Returns the value of attribute groupings.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def groupings
  @groupings
end

#serializersObject (readonly)

Returns the value of attribute serializers.



2
3
4
# File 'app/services/api_maker/abilities_loader.rb', line 2

def serializers
  @serializers
end

Instance Method Details

#load_abilities_with_conditions(ability_names) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'app/services/api_maker/abilities_loader.rb', line 86

def load_abilities_with_conditions(ability_names)
  Rails.logger.debug { "API maker: Loading abilities with conditions through query: [#{ability_names.join(", ")}], #{model_class}" }

  model_ids = model_class
    .accessible_by(ability, ability_names.first)
    .where(id: serializers.map(&:id))
    .pluck(model_class.primary_key)

  serializers.each do |serializer|
    ability_names.each do |ability_name|
      serializer.load_ability(ability_name, model_ids.include?(serializer.id))
    end
  end
end

#load_abilities_with_no_conditionsObject



68
69
70
71
72
73
74
75
# File 'app/services/api_maker/abilities_loader.rb', line 68

def load_abilities_with_no_conditions
  Rails.logger.debug { "API maker: Loading abilities with no condition: [#{abilities_with_no_conditions.join(", ")}], #{model_class}" }
  abilities_with_no_conditions.each do |ability_name|
    serializers.each do |serializer|
      serializer.load_ability(ability_name, true)
    end
  end
end

#load_abilities_with_no_rulesObject



77
78
79
80
81
82
83
84
# File 'app/services/api_maker/abilities_loader.rb', line 77

def load_abilities_with_no_rules
  Rails.logger.debug { "API maker: Loading abilities with no rules: [#{abilities_with_no_rules.join(", ")}], #{model_class}" }
  abilities_with_no_rules.each do |ability_name|
    serializers.each do |serializer|
      serializer.load_ability(ability_name, false)
    end
  end
end

#model_classObject



101
102
103
# File 'app/services/api_maker/abilities_loader.rb', line 101

def model_class
  @model_class ||= serializers.first.model.class
end

#performObject



14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'app/services/api_maker/abilities_loader.rb', line 14

def perform
  scan_abilities
  scan_groupings

  load_abilities_with_no_conditions if abilities_with_no_conditions.any?
  load_abilities_with_no_rules if abilities_with_no_rules.any?

  groupings.each_value do |ability_names|
    load_abilities_with_conditions(ability_names)
  end

  succeed!
end

#scan_abilitiesObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'app/services/api_maker/abilities_loader.rb', line 28

def scan_abilities
  abilities.each do |ability_name|
    abilities_data[ability_name] = {
      combined_conditions: [],
      rules_count: 0,
      rule_with_no_conditions: false
    }

    relevant_rules = ability.__send__(:relevant_rules, ability_name, model_class)
    relevant_rules.each do |can_can_rule|
      abilities_data[ability_name][:combined_conditions] << can_can_rule.conditions.to_s
      abilities_data[ability_name][:rules_count] += 1

      if can_can_rule.__send__(:conditions_empty?)
        abilities_data[ability_name][:rule_with_no_conditions] = true
        abilities_with_no_conditions << ability_name
      end
    end
  end
end

#scan_groupingsObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'app/services/api_maker/abilities_loader.rb', line 49

def scan_groupings
  abilities_data.each do |ability_name, ability_data|
    # No reason to create a group with no conditions - we are giving access to these without doing a query elsewhere
    next if ability_data.fetch(:rule_with_no_conditions)

    # If no rules have been defined, then we can safely assume no access without doing a query elsewhere
    if ability_data.fetch(:rules_count).zero?
      abilities_with_no_rules << ability_name
    else
      identifier = ability_data[:combined_conditions].join("___")

      groupings[identifier] ||= []
      groupings[identifier] << ability_name
    end
  end

  groupings
end