ruby-on-railsruby-on-rails-6rails-enginesrails-models

Can't mount newly generated Rails engine in an app


I have a complex Rails app and I want to extract some core functionality into an engine so that I can reuse the models etc in other Rails apps.

I've been following the official documentation for engines (https://guides.rubyonrails.org/engines.html). I'm able to create a new engine inside the app and generate some test models

> rails plugin new testengine --mountable

testengine> rails generate model Test

This is the .gemspec

require_relative "lib/testengine/version"

Gem::Specification.new do |spec|
  spec.name        = "testengine"
  spec.version     = Testengine::VERSION
  spec.authors     = ["Me"]
  spec.summary     = "testengine"

  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
  # to allow pushing to a single host or delete this section to allow pushing to any host.
  spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"

  spec.files = Dir["{app,config,db,lib}/**/*", "Rakefile", "README.md"]

  spec.add_dependency "rails", "~> 6.1.4"
end

I console into the test dummy rails app in testengine, and I can find my new model at Testengine::Test, no problem. So far so good.

Now I get to section 4.1 Mounting the Engine. I add the engine via the Gemfile file (in fact this is already done for me thanks to the rails generator above).

gem 'testengine', path: 'testengine'

Then I install my gems without problems.

> bundle install
...
Using testengine 0.1.0 from source at `testengine`
...

I console into the main app and I can find Testengine and Testengine::VERSION but not Testengine::Engine or Testengine::Test.

Reading a little further the docs say you need add this line to config/routes.rb

mount Testengine::Engine, at: "/testengine"

I do and now the rails app won't even start

config/routes.rb:3:in `block in <top (required)>': uninitialized constant Testengine::Engine (NameError)

What did I miss?


Solution

  • I will answer my question for the benefit of others who might make the same mistake I made. In my case, gem 'testengine', path: 'testengine' was buried inside a group of gems e.g. in

    group :test do
        ...
    end
    

    I guess I was confused how rails loads gems from groups and missed the detail about group inclusion. It seems that while it'll show in the list during bundle install, and autoload some basic items, such as Testengine::VERSION it doesn't autoload everything unless you are running an environment as the same name as the group. In hindsight, this seems a bit obvious. Lesson learned.