Module: Compony::ComponentMixins::Default::Standalone
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/compony/component_mixins/default/standalone.rb,
lib/compony/component_mixins/default/standalone/verb_dsl.rb,
lib/compony/component_mixins/default/standalone/standalone_dsl.rb,
lib/compony/component_mixins/default/standalone/resourceful_verb_dsl.rb
Overview
This contains all default component logic concerning standalone functionality. The module is included in every component.
Defined Under Namespace
Classes: ResourcefulVerbDsl, StandaloneDsl, VerbDsl
Instance Method Summary collapse
-
#clear_standalone! ⇒ Object
protected
Undoes previous standalone calls.
-
#on_standalone_access(verb_config, controller) ⇒ Object
Called by compony_controller when a request is issued.
-
#render_standalone(controller, status: nil, standalone_name: nil) ⇒ Object
Renders the component using the controller passed to it upon instanciation (calls the controller's render) Do not overwrite.
-
#standalone(name = nil, **nargs, &block) ⇒ Object
protected
DSL method This can be called multiple times to make a component listen to multiple paths.
-
#standalone_access_permitted_for?(controller, standalone_name: nil, verb: nil) ⇒ Boolean
Call this on a standalone component to find out whether default GET access is permitted for the current user.
Instance Method Details
#clear_standalone! ⇒ Object (protected)
Undoes previous standalone calls
122 123 124 |
# File 'lib/compony/component_mixins/default/standalone.rb', line 122 def clear_standalone! @standalone_configs = {} end |
#on_standalone_access(verb_config, controller) ⇒ Object
Called by compony_controller when a request is issued. This is the entrypoint where a request enters the Component world.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/compony/component_mixins/default/standalone.rb', line 21 def on_standalone_access(verb_config, controller) # Register as root comp if parent_comp.nil? fail "#{inspect} is attempting to become root component, but #{root_comp.inspect} is already root." if Compony.root_comp.present? RequestStore.store[:compony_root_comp] = self end # Prepare the request context in which the innermost DSL calls will be executed request_context = RequestContext.new(self, controller) ###===--- # Dispatch request to component. Empty Dslblend base objects are used to provide multiple contexts to the authorize and respond blocks. # Lifecycle is (see also "doc/Resourceful Lifecycle.pdf"): # - load data (optional, speficied ResourcefulVerbDsl, by convention, should default to the implementation in Resourceful) # - after_load_data (optional, specified in Resourceful) # - assign_attributes (optional, speficied ResourcefulVerbDsl, by convention, should default to the implementation in Resourceful) # - after_assign_attributes (optional, specified in Resourceful) # - authorize # - store_data (optional, speficied ResourcefulVerbDsl, by convention, should default to the implementation in Resourceful) # - respond (typically either redirect or render standalone, specified in VerbDsl), which defaults to render_standalone, performing: # - before_render # - render (unless before_render already redirected) ###===--- if verb_config.load_data_block request_context.evaluate_with_backfire(&verb_config.load_data_block) if global_after_load_data_block request_context.evaluate_with_backfire(&global_after_load_data_block) end end if verb_config.assign_attributes_block request_context.evaluate_with_backfire(&verb_config.assign_attributes_block) if global_after_assign_attributes_block request_context.evaluate_with_backfire(&global_after_assign_attributes_block) end end # TODO: Make much prettier, providing message, action, subject and conditions fail CanCan::AccessDenied, [inspect, verb_config..inspect].join(', ') unless request_context.evaluate(&verb_config.) if verb_config.store_data_block request_context.evaluate_with_backfire(&verb_config.store_data_block) end # Check if there is a specific respond block for the format. # If there isn't, fallback to the nil respond block, which defaults to `render_standalone`. respond_block = verb_config.respond_blocks[controller.request.format.symbol] || verb_config.respond_blocks[nil] request_context.evaluate(&respond_block) end |
#render_standalone(controller, status: nil, standalone_name: nil) ⇒ Object
Renders the component using the controller passed to it upon instanciation (calls the controller's render) Do not overwrite
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/compony/component_mixins/default/standalone.rb', line 89 def render_standalone(controller, status: nil, standalone_name: nil) # Start the render process. This produces a nil value if before_render has already produced a response, e.g. a redirect. rendered_html = render(controller, standalone: true) if rendered_html.present? # If nil, a response body was already produced in the controller and we take no action here (would have DoubleRenderError) opts = { html: rendered_html, layout: @standalone_configs[standalone_name].layout } opts[:status] = status if status.present? controller.respond_to do |format| # Form posts trigger format types turbo stream and then html, turbo stream wins. # For this reason, Rails prefers stream, in which case the layout is disabled, regardless of the option. # To mitigate this, we use respond_to to force a HTML-only response. format.html { controller.render(**opts) } end end end |
#standalone(name = nil, **nargs, &block) ⇒ Object (protected)
DSL method
This can be called multiple times to make a component listen to multiple paths. Each standalone config (path) has a name, the default being nil
.
To have a component listen to multiple paths, call standalone again and provide a name, e.g.: standalone(:autocomplete, path: 'foo/bar/autocomplete')
The kwarg parameter path
is handled analog to the Rails route path
111 112 113 114 115 116 117 118 119 |
# File 'lib/compony/component_mixins/default/standalone.rb', line 111 def standalone(name = nil, *, **nargs, &block) block = proc {} unless block_given? # If called without a block, must default to an empty block to provide a binding to the DSL. name = name&.to_sym # nil name is the most common case if @standalone_configs[name] @standalone_configs[name].deep_merge! StandaloneDsl.new(self, name, *, provide_defaults: false, **nargs).to_conf(&block) else @standalone_configs[name] = Compony::MethodAccessibleHash.new(StandaloneDsl.new(self, name, *, provide_defaults: true, **nargs).to_conf(&block)) end end |
#standalone_access_permitted_for?(controller, standalone_name: nil, verb: nil) ⇒ Boolean
Call this on a standalone component to find out whether default GET access is permitted for the current user. This is useful to hide/disable buttons leading to components a user may not press. For resourceful components, before calling this, you must have loaded date beforehand, for instance in one of the following ways:
- when called standalone (via request to the component), the load data step must be completed
- when called to check for permission only, e.g. to display a button to it, initialize the component by passing the :data keyword to
new
By default, this checks the authorization to access the main standalone entrypoint (with namenil
) and HTTP verb GET.
78 79 80 81 82 83 84 85 |
# File 'lib/compony/component_mixins/default/standalone.rb', line 78 def standalone_access_permitted_for?(controller, standalone_name: nil, verb: nil) verb ||= :get standalone_name = standalone_name&.to_sym verb = verb.to_sym standalone_config = standalone_configs[standalone_name] || fail("#{inspect} does not provide the standalone config #{standalone_config.inspect}.") verb = standalone_config.verbs[verb] || fail("#{inspect} standalone config #{standalone_config.inspect} does not provide verb #{verb.inspect}.") return RequestContext.new(self, controller).evaluate(&verb.) end |