Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to develop a Rails3 engine against a real app, using RSpec?

A lot has been written about engine development, and using a dummy app for testing.

In our case we're developing an engine that is not a stand-alone entity, but has dependencies on a real Rails 3 application. We still want this code to live in an engine, and not become part of the app, because the engine's job is to import data from a legacy system that has its own tables and model mappings, and we want to eventually remove it again.

The data mappings between the old legacy tables and the new schema are complex, and we want to TDD (using rspec) the engine.

  • I've followed Jose Valim's book "Crafting Rails Appliations" and am using the enginex gem.
  • I've replaced /spec/dummy_app with a git submodule pointing to a real Rails 3 app.
  • I'm having trouble loading the models from the engine (undefined symbol errors), as the real app's Gemfile doesn't point to the engine, and I also can't modify config/application.rb, to require the engine (which is what the dummy app does, as explained on pages 15-16 of the book).
  • I'm including the engine's lib folder into the load path $: in spec_helper and the paths are available.
  • Putting the require into spec_helper.rb didn't solve the problem.
  • I'm wondering if there is an internal Rails API (or a clever monkey patch) to hook into the boot sequence of the real app and require the engine, without having to modify the real app's code (as it's in a submodule).
  • Another issue I'm not fully sure about is that I have 2 Gemfiles (one in the engine and one in the app), and when the engine is active, they should both be used.

Thoughts?

like image 955
Wolfram Arnold Avatar asked Feb 23 '23 16:02

Wolfram Arnold


1 Answers

So, I figured out a few things and will answer my own question, now that I got it to work.

For simplicity, I'm going to refer to the name of my gem as "my_gem" and "MyGem":

In the engine.rb file, I added:

require 'my_gem'
require 'rails'

This fixed errors of the type:

my_gem/lib/my_gem/engine.rb:2: uninitialized constant MyGem::Rails (NameError)

In spec_helper.rb, I added right up top:

require 'bundler/setup'
require 'my_gem'

This is to make sure Bundler is initialized right away, and not through the app. That way I can load MyGem here, and it'll be hooked into the initialization sequence of the app. This fixes NameError exceptions for the engine's model classes.

That leaves the question of what Gemfile to use. The trouble is that my app has its own gemfile and the gem/engine needs its separate dependencies in its own Gemfile.

I couldn't find any API for Bundler to pass two Gemfile to it, in fact Bundler seems to be built around the assumption of a single authoritative Gemfile. So I generate one in spec_helper. I take the app's gemfile and append gemspec which points to the gem's dependency in GemSpec format. (The hint about gemspec is missing from Jose Valim's book by the way).

I don't know if there's a better way than concatenating files during test startup. If you know of one, please respond.

Helpful resources were:

  • Clarifying the Roles of the .gemspec and Gemfile by Yehuda Katz
  • Bundler Documentation for gemspec
like image 123
Wolfram Arnold Avatar answered Mar 08 '23 11:03

Wolfram Arnold