How to manage dependencies between my ruby projects? - ruby

This sounds like a basic question, but I can't find any answer to it on the Internet.
So I have a git ruby project database_models. It's a gem. I want 3 other project to use it. I've added a dependency on this project to those 3 projects like this:
gem "database_models", :git => "path", :branch => master
Now, I want a a develop branch of those 3 projects to use the develop branch of database_models, and I want a master branch of those 3 projects to use the master branch of database_models, so that my production environment is stable and independent of my development environment.
I can see 4 options of doing this, and I don't like any of them:
Deploy database_models to the server, and update those 3 projects to reference database_models using a path, instead of git
Git submodule
User different versions of database_models gem (1.1, 1.2, 1.3...). I would probably need my own gem server for that, right?
Write some code in a Gemfile that would choose the correct branch based on the environment where "bundle install" is run.

Usually you'd use Bundler with a local path. Your Gemfile points to the Git or Github repo using git or github:
gem 'spree', github: 'spree/spree', branch: 'master'
Note that includes the branch. You can make each of your projects use a different branch of your gem if you want to. You can make each of your projects use a different branch of your gem if you want to. You can also use groups to deploy different versions of your gem depending on the environment:
group :development, :test
gem 'spree', github: 'spree/spree', branch: 'bleedinedge'
end
group :staging, :production
gem 'spree', github: 'spree/spree', branch: 'master'
end
The above will work fine as long as you keep pushing to the Github. But thanks to local config, you can run the following on your command line:
bundle config local.database_modules ~/Projects/gems/spree
That will add a line to your ~/.bundle/config, so when you run bundle in your projects, it will pull it from your local repo.

User different versions of database_models gem (1.1, 1.2, 1.3...). I would probably need my own gem server for that, right?
I would do this and simply have my Gemfile select the correct gem via a tag. Here is an example:
git 'https://github.com/rails/rails.git', tag: 'v5.0.0'
So you can do the same while storing your custom gem on github (no gem server required).
Here is how to use tags with Git.
This should give you the flexibility you need.

Related

Using local gem with Bundler

I created an in-house gem to use with a Rails project that I want to include in my Gemfile.
The gem is hosted in a private repo on Github.com (so :git is not an option) so I am assuming the best direction to include the gem is :path, e.g.
gem 'mygem', :path => '/path/to/gem/dir'
I am curious though:
Where is the ideal place for the gem to be included? (vendor/ ?)
If vendor is the best place, then I don't need to add the gem to my project repository (since vendor/ is ignored by default)
I am using Capistrano to deploy my project; how should Capistrano be aware of the local gem so that it can deploy it as well?
You can go for the vendor location and have the authentication information for the private gem in the gemfile like this:
gem 'foo', :git => 'https://my_username:my_password#github.com/my_github_account/my_repo.git'
However, I am guessing that you will be uncomfortable exposing such sensitive information in the gemfile so you can use a git protocol based url in your gem file like this:
git://github.com/username/repo.git
git protocol based urls are read only so your private repo should be intact.
Also, I am sure you can write a capistrano task to deploy a private gem to vendor directory but that might involve putting in your github username/password in the capistrano task. Also, you can prompt for the username/password during deployment as opposed to putting it in the capistrano task.

Gemfile: Difference Between branch and ref in a github Reference

In the Gemfile it's possible to refer a gem hosted on github:
gem 'spree', github: 'spree/spree', branch: '2-3-stable'
gem 'spree_gateway', github: 'spree/spree_gateway', ref: '2-1-stable'
The Gemfile manpage describes three attributes for git: branch, ref and tag. What's the difference between ref and branch? And how does bundler handle the gems differently depending on the attribute?
This especially seems to be interesting because you can only use one of the attributes at a time.
With branch, you're just specifying the git branch to pull from. If you did a bundle up <gem> when targeting a branch, it would update to the tip of that branch.
The ref is really nailing it down to an individual commit. You wouldn't give a "human-readable" name as you did in your question, you'd do something like:
gem 'something', github: 'someone/something', ref: '832e76a9'
And now you've pinned it to that ref. If you did a bundle up something, it wouldn't change that gem (it may update its dependencies though).

Dynamic branch name for git based gems

I am using bundler to deploy gems from an in house git repository into my rails app. I would like to have different branch names for different groups, however, this:
group :production, :release_candidate, :staging, :demo do
gem "my_inhouse_gem", '0.0.1', git: 'git#github.com:my_gem.git', branch: 'master'
end
group :development, :develop do
gem "my_inhouse_gem", '0.0.1', git: 'git#github.com:my_gem.git', branch: 'develop'
end
fails with
You cannot specify the same gem twice coming from different sources.
You specified that mygem (= 0.0.1) should come from
git#github.com:my_gem.git (at develop) and
git#github.com:my_gem.git (at master)
While the following:
group :production, :release_candidate, :staging, :demo do
my_gem = 'master'
end
group :development, :develop do
my_gem = "develop"
end
gem "my_inhouse_gem", '0.0.1', git: 'git#github.com:my_gem.git', branch: my_gem
Simply uses whichever group is printed last.
After reading up on it and finding this article: http://yehudakatz.com/2010/05/09/the-how-and-why-of-bundler-groups/ ,I realize this is because bundler will still execute the contents of every group, and then simply install the ones that match.
How can I have a dynamic branch name based on environment config in my Gemfile?
Bundler isn't designed to handle this situation the way that you'd like. It's intended to provide a consistent set of gems. Groups can control which gems are installed in what environments, but not to switch the version of a gem.
There may be a better way to accomplish what you want. If you need to develop against an experimental version of a gem, you're probably better off doing it in a branch of your project.
See also: https://github.com/bundler/bundler/issues/751#issuecomment-22113199
This is how I worked around the issue:
At the top of my Gemfile:
rails = ENV['RAILS_ENV'] || 'default'
And then:
if rails.match /develop/i or rails.match /ci/ or rails.match /test/ or rails.match /default/i
# if you wish to test locally against your branch
#in_house_version = 'your_branch'
in_house_version = 'develop'
else
in_house_version = 'master'
end

Ruby: How to Install a Plugin in a Git Repository

I'm not new to programming, but brand new to Ruby. Everything's working, but I'm still missing a key concept: how do you install a plugin and where/how do you include it in an app?
Example:
I'm trying to use the Facebooker2 plugin: https://github.com/mmangino/facebooker2. In the readme, step 1 is to "Install facebooker2 as a plugin in your rails app." I've run the command git clone https://github.com/mmangino/facebooker2.git to download a read only version of the repository.
Do I then bundle that up using Bundler, or do I need to create a gem file in some way? Do I simply
use gem to install it, or do I need to compile it into a gem?
Any help (terminal commands or otherwise) are extremely helpful.
I looked at the repo and it's set up as a gem. You can simply add
gem 'facebooker2'
to your Gemfile (in the root of your project) and run
bundle install
to download it and add it to your list of installed gems, both in development and in production.
Rails used to include the concept of plugins (added to your /vendor/plugins directory) but that's been dropped in favor of gems.
If you're source is source 'https://rubygems.org' but the gem you need is specific to github and not part of the rubygems.org library, then you can add the git method to your gemfile. You can also select a specific branch version. For example, here I have the gem cancan being pulled from the github repository on the 2.0 branch.
gem "cancan", :git => "git://github.com/ryanb/cancan.git", :branch => "2.0"

Bundler: always use latest revision of git branch in Gemfile

I have a Gemfile with a private git repo in the following format:
gem 'magic_beans', :git => "git#git.example.com:magic_beans.git', :branch => 'super_beans'
When I bundle install, the Gemfile.lock locks it to a specific SHA revision.
Can I get bundler to always check and use the latest SHA commit and/or update the Gemfile.lock? Notice that when I push updates to the super_beans branch I am not modifying the gem version.
Ideally, every time I run bundle it would check upstream git repo for a newer SHA revision of the branch.
This isn't how bundler works.
The point is to allow seamless versioning of dependencies.
(particularly so you know exactly what version of the code is deployed at any given time).
If want the latest version, you should just run.
bundle update magic_beans
This is exactly the same functionality as if you just say
gem "rails"
I'd suggest though, if you have a range of specific things you want to update
then add a custom binary (say an executable file named bundle_update)
#!/usr/bin/env bash
bundle install
bundle update magic_beans
Then just do a ./bundle_update when you want to update these things.
You can run bundle update to update all or specific gems to their latest available version, as stated in the docs.
Would that help?
After searching through the documents I finally found the magic way to do this:
bundle update magic_beans --source magic_beans
That is to update the magic_beans gem only, but not to touch other locked gems. The doc about this is: http://bundler.io/man/bundle-update.1.html
delete .gemlock is what worked for me :/

Resources