class ViewModel::AccessControl::Composed
Provides access control as a combination of `x_if!` and `x_unless!` checks for each access check (visible, editable, edit_valid). An action is permitted if at least one `if` check and no `unless` checks succeed. For example:
edit_valid_if!("logged in as specified user") { ... } edit_valid_unless!("user is on fire") { ... }
Constants
- ComposedResult
- PermissionsCheck
Attributes
edit_valid_ifs[R]
edit_valid_unlesses[R]
editable_ifs[R]
editable_unlesses[R]
visible_ifs[R]
visible_unlesses[R]
Public Class Methods
each_check(check_name, include_ancestor = nil) { |x| ... }
click to toggle source
# File lib/view_model/access_control/composed.rb, line 147 def each_check(check_name, include_ancestor = nil) return enum_for(:each_check, check_name, include_ancestor) unless block_given? self.public_send(check_name).each { |x| yield x } visited = Set.new @included_checkers.each do |ancestor| next unless visited.add?(ancestor) next if include_ancestor && !include_ancestor.call(ancestor) ancestor.each_check(check_name) { |x| yield x } end end
edit_valid_if!(reason, &block)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 133 def edit_valid_if!(reason, &block) @edit_valid_ifs << new_permission_check(reason, &block) end
edit_valid_unless!(reason, &block)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 137 def edit_valid_unless!(reason, &block) @edit_valid_unlesses << new_permission_check(reason, &block) end
editable_if!(reason, &block)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 125 def editable_if!(reason, &block) @editable_ifs << new_permission_check(reason, &block) end
editable_unless!(reason, &block)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 129 def editable_unless!(reason, &block) @editable_unlesses << new_permission_check(reason, &block) end
include_from(ancestor)
click to toggle source
Configuration API
# File lib/view_model/access_control/composed.rb, line 109 def include_from(ancestor) unless ancestor < ViewModel::AccessControl::Composed raise ArgumentError.new("Invalid ancestor: #{ancestor}") end @included_checkers << ancestor end
inherited(subclass)
click to toggle source
Calls superclass method
ViewModel::Callbacks#inherited
# File lib/view_model/access_control/composed.rb, line 90 def inherited(subclass) super subclass.initialize_as_composed_access_control end
initialize_as_composed_access_control()
click to toggle source
# File lib/view_model/access_control/composed.rb, line 95 def initialize_as_composed_access_control @included_checkers = [] @edit_valid_ifs = [] @edit_valid_unlesses = [] @editable_ifs = [] @editable_unlesses = [] @visible_ifs = [] @visible_unlesses = [] end
inspect()
click to toggle source
Calls superclass method
# File lib/view_model/access_control/composed.rb, line 161 def inspect s = super + '(' s += inspect_checks.join(', ') s += " includes checkers: #{@included_checkers.inspect}" if @included_checkers.present? s += ')' s end
inspect_checks()
click to toggle source
# File lib/view_model/access_control/composed.rb, line 169 def inspect_checks checks = [] checks << "visible_if: #{@visible_ifs.map(&:reason)}" if @visible_ifs.present? checks << "visible_unless: #{@visible_unlesses.map(&:reason)}" if @visible_unlesses.present? checks << "editable_if: #{@editable_ifs.map(&:reason)}" if @editable_ifs.present? checks << "editable_unless: #{@editable_unlesses.map(&:reason)}" if @editable_unlesses.present? checks << "edit_valid_if: #{@edit_valid_ifs.map(&:reason)}" if @edit_valid_ifs.present? checks << "edit_valid_unless: #{@edit_valid_unlesses.map(&:reason)}" if @edit_valid_unlesses.present? checks end
new_permission_check(reason, error_type: ViewModel::AccessControlError, &block)
click to toggle source
Implementation
# File lib/view_model/access_control/composed.rb, line 143 def new_permission_check(reason, error_type: ViewModel::AccessControlError, &block) PermissionsCheck.new(self.name&.demodulize, reason, error_type, block) end
visible_if!(reason, &block)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 117 def visible_if!(reason, &block) @visible_ifs << new_permission_check(reason, &block) end
visible_unless!(reason, &block)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 121 def visible_unless!(reason, &block) @visible_unlesses << new_permission_check(reason, &block) end
Public Instance Methods
editable_check(traversal_env)
click to toggle source
final
# File lib/view_model/access_control/composed.rb, line 187 def editable_check(traversal_env) check_delegates(traversal_env, self.class.each_check(:editable_ifs), self.class.each_check(:editable_unlesses)) end
valid_edit_check(traversal_env)
click to toggle source
final
# File lib/view_model/access_control/composed.rb, line 192 def valid_edit_check(traversal_env) check_delegates(traversal_env, self.class.each_check(:edit_valid_ifs), self.class.each_check(:edit_valid_unlesses)) end
visible_check(traversal_env)
click to toggle source
final
# File lib/view_model/access_control/composed.rb, line 182 def visible_check(traversal_env) check_delegates(traversal_env, self.class.each_check(:visible_ifs), self.class.each_check(:visible_unlesses)) end
Protected Instance Methods
check_delegates(env, ifs, unlesses)
click to toggle source
# File lib/view_model/access_control/composed.rb, line 198 def check_delegates(env, ifs, unlesses) vetoed_checker = unlesses.detect { |checker| checker.check(env) } veto = vetoed_checker.present? if veto veto_error = vetoed_checker.error_type.new('Action not permitted because: ' + vetoed_checker.reason, env.view.blame_reference) end allow = ifs.any? { |checker| checker.check(env) } unless allow allow_error = NoRequiredConditionsError.new(env.view.blame_reference, ifs.map(&:name)) end ComposedResult.new(allow, veto, allow_error, veto_error) end