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?
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.