Question

tl;dr

I'm trying to break out a part of a larger application as a mountable engine. The engine will exist in different flavors, each contained in their own gem. I can't get the gem name be different from the engine constant name.

Details

The extracted part contains logic for registration, authentication and session handling. The application is used by clients in different parts of the world with different requirements and regulations regarding the end customers using the product. This prompted us to create separate modules for these needs for each regulatory region. They currently live in the lib directory and the different implementations are loaded depending on config.

The goal with the engines is that you mount the appropriate engine and the routes file routes all the concerned calls to the engine.

Since we have several such registration modules, and more to come, we need to maintain several gems for the variants. I'm trying to make it so that the gems have different names (auth_A, auth_B, etc) but the contained engine has the same contant name, Auth::Engine.

That way we can include the correct gem in the Gemfile and the rest will just work since the endpoint it should rout to is always the same regardless of what version is running.

Problem

The problem I run in to is that I can't seam to get the gem to have one name and the engine constant another...

If I generate a new engine names auth it works fine to mount it in the main app. If I then change the gem name and containing folder to auth_a and update the host apps Gemfile it stops working, I can bundle fine but when I try to start the host app it fails when it ties to mount the engine, complaining that Auth::Engine is an undefined constant.

My, slightly redacted, gemspec looks like this:

$:.push File.expand_path("../lib", __FILE__)

# Maintain your gem's version:
require "auth/version"

# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
  s.name        = "auth_a"
  s.version     = Auth::VERSION
  s.authors     = ["Jonas Schubert Erlandsson"]
  s.email       = ["jonas.schubert.erlandsson@xxxxxx.com"]
  s.homepage    = "http://some.page.on/the/internet.html"
  s.summary     = "Authentication module for A"
  s.description = "This engine, when mounted in Host app, handles registration, account update, login and logout of users."

  s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
  s.test_files = Dir["test/**/*"]

  s.add_dependency "rails", "~> 3.2.13"
end

The only thing I have changed from the generated scaffold is s.name = "auth_a". The relevant line from the host apps Gemfile: gem 'auth_a', path: "../auth_a"...

I have looked through the entire source tree trying to find where it infers a name from the gem name but I can't see it. I don't know what I'm missing and the gem spec docs weren't much help for this either ... I didn't think that the gem name was bound to the constant names of the gem, but maybe I'm wrong? Can you override it? Or am I missing something else?

Was it helpful?

Solution

The answer to this was to simply add this to the line in the host apps Gemfile: gem 'auth_a', path: "../auth_a", require: 'auth'.

So it looks like it defaults to requiring, that is auto loading, a constant based on the gem name, but the require call tells it what to require instead.

Hope it helps someone else as well :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top