component-based-rails-applications-book icon indicating copy to clipboard operation
component-based-rails-applications-book copied to clipboard

Suggestion: Discuss autoloading implications

Open dwieringa opened this issue 6 years ago • 1 comments

I just got bit my an autoloading issue.

In my current scenario, I have a Rails 5.0 app where I previously added two related "apps" to via namespacing. After having discovered CBRA, I've start adding more related apps as components.

My first step was to pull out a Single Sign On portion of the host app into a component. I then added another app as a 2nd component.

My issue was that when I moved SessionsController from the host app to a component folder, I didn't think/know to add require_dependency "single_sign_on/application_controller" as the first line. That line gets added to engine controllers by the rails plugin generator, but it's something I've missed when I copy or create engine controllers by hand.

Without the require_dependency line, things become unreliable in dev due to autoloading. Sometimes Rails picks up the ApplicationController from the host app and sometimes from the component (and maybe sometimes from other components?). In my case, the host app ApplicationController was doing things like before_action :check_authenticated, but my single_sign_on's ApplicationController was not. ...when the wrong ApplicationController got loaded into SessionController the app broke...but its mood varied between server restarts. Once I added the require_dependency, things became consistent/happy.

In quickly skimming the book, I'm noticing that...

  1. Chapter 2 discusses starting from scratch and using the generator so the issue doesn't come up
  2. Chapter 4 shows extracting from a component, so the require_dependency is already there
  3. In Chapter 5, the example doesn't have controllers

So currently this doesn't get touched on, but I think it would be a common pitfall for people breaking apart an existing app. ...and for people accustomed to creating controllers by hand vs the generator.

More information: https://stackoverflow.com/a/37102667/3352624

dwieringa avatar Feb 01 '19 14:02 dwieringa

This is a very good point! (and oh so facepalm subtle...)

If you use mountable engines (i.e., all code chapters 1-4), my suggestion is to getting into the habit of referencing all classes with their namespace explicitly. I.e., always inherit from SingleSignOn::ApplicationController. This will break the autoloading issue because ::ApplicationController can no longer "satisfy" the class name search Ruby performs.

I am going to speculate that this problem almost exclusively exists with inheritance because this happens (can happen) when not all files have been loaded (as the files get parsed). Once all the files are loaded, Ruby will prefer SingleSignOn::ApplicationController over ::ApplicationController even if you don't explictly use the namespace. I.e., most references within methods should not be able to cause this problem.

The component extraction described in Chapter 5 does not directly allow for this solution as no namespace gets introduced. That said, I don't recommend creating more than the initial component in this way, so any subsequent components would have a namespace and be able to be differentiated.

Thanks for referencing the stack overflow issue - I added my comment there too.

shageman avatar Feb 04 '19 16:02 shageman