class ViewModel::AccessControl
Defines an access control discipline for a given action against a viewmodel.
Access control is based around three edit check hooks: visible, editable and valid_edit. The visible determines whether a view can be seen. The editable check determines whether a view in its current state is eligible to be changed. The valid_edit change determines whether an attempted change is permitted. Each edit check returns a pair of boolean success and optional exception to raise.
Constants
- Result
Public Class Methods
# File lib/view_model/access_control.rb, line 39 def initialize @initial_editability_store = {} end
Public Instance Methods
# File lib/view_model/access_control.rb, line 82 def editable!(view, deserialize_context:, changes:) run_callback(ViewModel::Callbacks::Hook::BeforeVisit, view, deserialize_context) run_callback(ViewModel::Callbacks::Hook::BeforeDeserialize, view, deserialize_context) run_callback(ViewModel::Callbacks::Hook::OnChange, view, deserialize_context, changes: changes) if changes run_callback(ViewModel::Callbacks::Hook::AfterDeserialize, view, deserialize_context, changes: changes) run_callback(ViewModel::Callbacks::Hook::AfterVisit, view, deserialize_context) end
Check that the record is eligible to be changed in its current state, in the given context. This must be called before any edits have taken place (thus checking against the initial state of the viewmodel), and if editing is denied, an error must be raised only if an edit is later attempted. To be overridden by viewmodel implementations.
# File lib/view_model/access_control.rb, line 59 def editable_check(_traversal_env) Result::DENY end
Once the changes to be made to the viewmodel are known, check that the attempted changes are permitted in the given context. For viewmodels with transactional backing models, the changes may be made in advance to give the edit checks the opportunity to compare values. To be overridden by viewmodel implementations.
# File lib/view_model/access_control.rb, line 68 def valid_edit_check(_traversal_env) Result::DENY end
Wrappers to check access control for a single view directly. Because the checking is run directly on one node without any tree context, it's only valid to run:
-
on root views
-
when no children could contribute to the result
# File lib/view_model/access_control.rb, line 77 def visible!(view, context:) run_callback(ViewModel::Callbacks::Hook::BeforeVisit, view, context) run_callback(ViewModel::Callbacks::Hook::AfterVisit, view, context) end
Check that the user is permitted to view the record in its current state, in the given context.
# File lib/view_model/access_control.rb, line 45 def visible_check(_traversal_env) Result::DENY end
Private Instance Methods
# File lib/view_model/access_control.rb, line 145 def cleanup_editability(view) @initial_editability_store.delete(view.object_id) end
# File lib/view_model/access_control.rb, line 137 def fetch_editability(view) unless @initial_editability_store.has_key?(view.object_id) raise RuntimeError.new("No access control data recorded for view #{view.to_reference}") end @initial_editability_store.delete(view.object_id) end
# File lib/view_model/access_control.rb, line 149 def raise_if_error!(result) raise (result.error || yield) unless result.permit? end
# File lib/view_model/access_control.rb, line 129 def save_editability(view, initial_editability) if @initial_editability_store.has_key?(view.object_id) raise RuntimeError.new("Access control data already recorded for view #{view.to_reference}") end @initial_editability_store[view.object_id] = initial_editability end