Howdy,
While working on Katello as an isolated engine and most recently attempting
to add the new plugin definition to Katello as an engine I have encountered
a number of issues with the way routing is handled for isolated engines.
I'd like to walk through each situation with some examples and get feedback
on ideas of how to proceed. Please consider what follows to be blocking,
and thus input sooner rather than later would be much appreciated.
General Problem: When using an isolated engine, the following is true:
a) the parent application code is not aware of the isolated engines routes
when the parent application is the entry point
b) the parent application code is not aware of the parent application's
routes when the isolated engine is the entry point
Examples of where this manifests:
- User Redirect
Redirecting a user to the login screen when accessing an isolated engine
page
Steps:
- Start Foreman with Katello as an engine
- Point browser to a Katello page (e.g.
http://myforeman.org/katello/products
Output:
"No route matches {:controller => "users", :action => "login"}
Potential Solution:
Use the 'main_app' helper for path resolution - see
https://github.com/theforeman/foreman/pull/1055 for an example in use
Issues:
- May require resolving all paths with main_app in foreman
- Organizations/Locations Redirect
Redirecting a user to organization/location pages when there is no initial
one of either, similar to (1)
Potential Solution:
This would require a similar solution to (1) above and require changing the
path calculations in
https://github.com/theforeman/foreman/blob/develop/app/controllers/application_controller.rb#L323to:
main_app.organizations_path
main_app.locations_path
Issues:
- May require resolving all paths with main_app in foreman
- Defining Menu Items
Using the new plugin definition to define a set of menu items
Steps:
- Create a new plugin that is an isolated engine
- Define a menu item as such:
menu :top_menu,
:products,
:url_hash => {:controller => 'katello/products', :action =>
'index'}
Output:
"No route matches {:controller => 'katello/products', :action => 'index'}
Potential Solution
Please see https://github.com/Katello/katello/pull/3446 and
https://github.com/theforeman/foreman/pull/1071
Basic idea is to make use of the 'railtie_routes_url_helpers' object that
is placed on the top level module object (in our case Katello). This set of
helpers knows the isolated engine paths, and thus we can include an extra
parameter in the plugin definition 'path' that contains the already
resolved path. This path is resolved on the Katello side where the paths
are known since the parent application cannot resolve (because it does not
know about) the engine routes.
Normally, the isolated engine paths are published onto an object named the
same as the engine. In other words, normally from the parent application or
isolated engine, one could do 'katello.products_path'. However, this helper
object is only available when accessing a controller and thus when defining
inside the plugin, we must use the aforementioned method of access the
helper methods.
Issues:
- How to handle authorization since this code -
https://github.com/theforeman/foreman/blob/develop/app/services/menu/item.rb#L31expects
a controller/action combination that it can resolve for handling
permission checks against an entity coming from the engine?
- Parent Path Resolution when Accessing Engine Page
When using a single navigation structure, engine pages would inherit the
base Foreman application layout and menu system and put their content into
the main page portion. Whenever a page that belongs to the isolated engine
is accessed, the entry point is the isolated engine; however, the menu most
be calculated and resolved just like if entering a page that belongs to the
parent application. This means that when entering an isolated engine page,
the "context" is that of the isolated engine who does not know about the
parent application routes directly. Thus, whenever the menu paths are
calculated an error is thrown because the engine cannot resolve the paths.
This largely manifests itself here -
https://github.com/theforeman/foreman/blob/develop/app/helpers/home_helper.rb#L29
When the link is generated, the function makes use of 'link_to' which in
turn calls 'url_for' and expects to make use of a hash that includes
':controller' and ':action'. However, when coming from the context of the
isolated engine, the controller and actions of the parent application
cannot be resolved.
Potential Solution:
- Enforce all menu items to be defined similar to (3) making use of a
'path' option that contains the already resolved path available upon link
computation link - Change the code to check if an action/controller belongs to the main_app
and use 'main_app.entity_path' to calculate the path, otherwise punt to
checking for a ':path' key - Require menu definitions to include a "resolver" object that all paths
are resolved against, e.g.
{:path => 'products_path', :resolver => katello}
{:path => 'hosts_path', :resolver => main_app}
resolver.send(:path)
Issues:
- Code could get messy
- Could be missing some caveats
- Developers could get confused on when to define their plugin and in what
way - Would the parent application, with two isolated engines, be able to
properly resolve the other engines routes depending upon the entry point?
Wrap Up:
The above outlines the 4 major locations and issues I have encountered thus
far using an isolated engine and attempting to move Katello under the
single navigation of Foreman using the new plugin system. Please make note
that in each case, I attempted to describe the problem, point out any steps
to reproduce, potential solutions and any issues I can forsee at this
moment. Before concluding, I'd like to point out the open questions I am
hoping others can help address.
- How do we handle isolated engines and routing in the parent application
in general? - Does using main_app everywhere paths are involved make sense? Is that
overkill? - Does anyone seen a cleaner solution to any of the above problems?
- Is the easier/better solution to avoid isolated engines all together for
Foreman?
Thanks,
Eric