Developing Multiple Rails Plugins with Dependencies

329 Views Asked by At

I'm starting to build a series of plugins and engines in a project I'm developing and I've run into the issue of having to list the paths to dependencies in all of the Gemfiles for the main application and the plugins/engines if I want rake to work.

Rake works fine for the main application because it's Gemfile lists the relative paths to the plugins/engines I want, but when a plugin/engine is dependent on another and does not have the relative paths all listed, using rake rdoc I'll get an error like the following (presumably I'll get the same error trying to run tests/the dummy application/etc):

Bundler could not find compatible versions for gem "user":
  In Gemfile:
    auth (>= 0) ruby depends on
      user (>= 0) ruby
Could not find gem 'user (>= 0) ruby', which is required by gem 'auth (>= 0) ruby', in any of the sources.

Rather than having to use paths, I've tried specifying the git repository in the plugins/engines like so:

# User engine
gem 'user', git: 'https://localhost/git/project/user.git', branch: 'master'

And then using bundler config local.user /path/to/local/repo command to make it point to a local repository for development. This appeared to work perfectly... until I change the version of the plugin in the local repo, then it spits out this error in any dependent plugin/engine/application:

Could not find user-0.0.1 in any of the sources
Run `bundle install` to install missing gems.

Whilst that isn't really much of an issue-- the version number will be changed at the end anyway --it also turns out that it will throw the following error if you're on a branch in the local repo instead of master:

Local override for user at /path/to/local/repo is using branch deleteme but Gemfile specifies master

And omitting the branch option from the Gemfile leaves me with this error:

Cannot use local override for user at /path/to/local/repo because :branch is not specified in Gemfile. Specify a branch or use `bundle config --delete` to remove the local override

So am I just stuck with having , path: "../local-repo-directory" strewn about all of the Gemfiles for plugins/engines with dependencies on one another whilst in development or is there a way of developing multiple interdependent plugins/engines for Rails at the same time that doesn't use a really sloppy/inelegant solution?

I'm drawing blanks on other ways to do this, so any help would be greatly appreciated. I hope I've explained this well enough, but if there's anything else I can clarify, let me know.

Thanks!

1

There are 1 best solutions below

0
Pierre Pretorius On

Stick with specifying git repositories in your Gemfile and using bundle local overrides to work on them.

Possible problems with solutions: 1. Local override for user at /path/to/local/repo is using branch deleteme but Gemfile specifies master If your Gemfile specifies branch "master" then the local override should have branch "master" checked out. This is because the goal of a local override is so that you can work on a gem in a local folder while running and testing the application. In production it will check out the branch and revision specified in the Gemfile and Gemfile.lock and it should offcourse be exactly what you are running with your local override.

2. Could not find user-0.0.1 in any of the sources Run `bundle install` to install missing gems. When you run bundle install it places a version number for each gem in the Gemfile.lock. This file is added to git so that other developers and your production server runs the same versions of the gems as you do. Your Gemfile.lock needs to specify the same version of your gem as what is returned in the local override gemspec file. If you incremented the version number in the local override you need to run "bundle update gemname" in the application that uses it so that it updates the Gemfile.lock. Note that bundler caches everything in a gemspec file until you increment the version. Thus you can't add new dependencies or change dependency versions in a gemspec if you don't increase the version number in that gemspec.

The git-bundle gem

If you use a git repository in your Gemfile with local overrides bundler will store git revision hashes in your Gemfile.lock as mentioned above. Example:

Gemfile: gem 'example', git: 'https://github.com/your_name/example.git', branch: :master

Bundle config shell command: bundle config local.example /path/to/local/git/repository

Gemfile.lock (auto generated): GIT remote: https://github.com/your_name/example.git revision: b9270e61abb89e1ff77fb8cfacb463e4d04388ad branch: master

After you commit in the local override repository you will need to run bundle install on your main application so that it rebuilds the Gemfile.lock to include the new revision hash and commit it. I recommend using the gem below as it automates this process for you and also aids in other scenarios. See the gem page for exact detail.

https://github.com/EPI-USE-Labs/git-bundle

The activesupport-decorators gem

As a sidenote, when you need to extend classes between your gems you can use the decorator pattern which is implemented elegantly by the activesupport-decorators gem:

https://github.com/EPI-USE-Labs/activesupport-decorators