Including the bundler gem itself in my Rails app - ruby

Bundler is great. But there's one gem that it won't work for, and that's the bundler gem itself, which still needs to be installed manually:
Could not load the bundler gem. Install it with `gem install bundler`.
Besides being an extra step, this opens the door to version incompatibilities with Bundler itself.
Is there a way to include Bundler itself in my app, so that it relies on the included bundler gem?

No. The ruby gems stay on the user environment, you can't distribute it with your project, the user need to install the bundler.
and Bundler can't bundle itself. :)

Related

Pin or lock version of a dependency gem installed as part of bundle install

I'm trying to work around a bug in the ffi Gem on Windows. I need to run bundle install on some project that I pulled from the internet. The problem is that bundle install is trying to install version 1.9.9 of ffi, which will error out.
Is there some way I can tell bundle install to install version 1.9.8 of ffi? Perhaps a command line parameter, or an addition to the Gemfile or Gemfile.lock?
One possible complication is that the Gemfile I'm dealing with does not list ffi at all, so it must be pulled in by one of the dependencies' dependencies.
Explicitly list the version of ffi you want in your Gemfile. That's what it's for:
gem 'ffi', '1.9.8'
If your Gemfile.lock already has ffi locked to version 1.9.9 (which is probably the case for you), you may have to run bundle update ffi after adding that to your Gemfile before bundle install will work correctly.

Bundler installing gem that's already installed

I believe I'm misunderstanding the way bundler works, but from the bundle install documentation it seems to indicate bundler will use locally installed system gems.
...
--system: Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application
...
The --system option is the default. Pass it to switch back after using the --path option as described below.
I'm not using rbenv/rvm or any other Ruby version manager. I'm using ChefDK as my primary development environment, which ships with Ruby and a bunch of preinstalled gems.
The full contents of the Gemfile, there is no Gemfile.lock yet.
source 'https://rubygems.org'
gem 'nokogiri', '1.6.3.1'
Local nokogiri installed
$ gem list --local | grep nokogiri
nokogiri (1.6.6.2, 1.6.3.1, 1.5.5)
System Gem location has nokogiri 1.6.3.1 installed
$ echo $GEM_HOME
/Users/arthur/.chefdk/gem/ruby/2.1.0
$ find /Users/arthur/.chefdk/gem/ruby/2.1.0 | grep nokogiri | grep 1.6.3.1
/Users/arthur/.chefdk/gem/ruby/2.1.0/cache/nokogiri-1.6.3.1.gem
/Users/arthur/.chefdk/gem/ruby/2.1.0/extensions/x86_64-darwin-12/2.1.0/nokogiri-1.6.3.1
/Users/arthur/.chefdk/gem/ruby/2.1.0/extensions/x86_64-darwin-12/2.1.0/nokogiri-1.6.3.1/mkmf.log
/Users/arthur/.chefdk/gem/ruby/2.1.0/gems/nokogiri-1.6.3.1
/Users/arthur/.chefdk/gem/ruby/2.1.0/gems/nokogiri-1.6.3.1/.autotest
/Users/arthur/.chefdk/gem/ruby/2.1.0/gems/nokogiri-1.6.3.1/.editorconfig
...
However, when I run a bundle install, it tries to install and compile libxml2 for nokogiri.
$ bundle install
Fetching gem metadata from https://rubygems.org/.........
Resolving dependencies...
Using mini_portile 0.6.0
Building nokogiri using packaged libraries.
Building libxml2-2.8.0 for nokogiri with the following patches applied:
- 0001-Fix-parser-local-buffers-size-problems.patch
- 0002-Fix-entities-local-buffers-size-problems.patch
- 0003-Fix-an-error-in-previous-commit.patch
- 0004-Fix-potential-out-of-bound-access.patch
- 0005-Detect-excessive-entities-expansion-upon-replacement.patch
- 0006-Do-not-fetch-external-parsed-entities.patch
- 0007-Enforce-XML_PARSER_EOF-state-handling-through-the-pa.patch
- 0008-Improve-handling-of-xmlStopParser.patch
- 0009-Fix-a-couple-of-return-without-value.patch
- 0010-Keep-non-significant-blanks-node-in-HTML-parser.patch
- 0011-Do-not-fetch-external-parameter-entities.patch
************************************************************************
IMPORTANT! Nokogiri builds and uses a packaged version of libxml2.
...
What am I missing? How can I force bundler to use the already installed nokogiri 1.6.3.1 (that ships with ChefDK)? I'm trying to avoid having nokogiri compile libxml2 because that fails consistently on many different developer/operations workstations and has caused no end of grief. Thanks.
Edit
Thanks to Tim Moore, using bundle env I noticed in the output that bundler had shared gems disabled.
$ bundle env
Bundler 1.7.12
Ruby 2.1.4 (2014-10-27 patchlevel 265) [x86_64-darwin12.0]
Rubygems 2.4.4
GEM_HOME /Users/arthur/.chefdk/gem/ruby/2.1.0
GEM_PATH /Users/arthur/.chefdk/gem/ruby/2.1.0:/opt/chefdk/embedded/lib/ruby/gems/2.1.0
Bundler settings
disable_shared_gems
Set for the current user (/Users/arthur/.bundle/config): "1"
Gemfile
source 'https://rubygems.org'
...
Looking at the ~/.bundle/config, sure enough the global config was set.
---
BUNDLE_DISABLE_SHARED_GEMS: '1'
Once removed, Bundler resolves nokogiri 1.6.3.1 correctly and doesn't try reinstalling it. This setting should not be there by default, by default bundler installs with --system. I must have set this setting many months back and forgot I did.
Try running bundle env to verify that the install location is what you expect.
If not, check whether there is a .bundle/config or ~/.bundle/config file overriding the install path. The output of bundle env will tell you what configuration it is using and how it was determined (i.e., which file it was in or whether it was picked up from an environment variable).
Try removing all contents of gemfile.lock file. Save the file. Run bundle install again.
There are a couple of methods. In gemfile you can specify the path which will force bundle to use from there.
gem "my_gem", :path => "path to gem"
As i see the issue is with the default paths here. Try doing this.
ChefDK doesn't install gems globally, it installs them under /opt/chefdk so they won't interfere with "your" global gems. I suggest you leave ChefDK gems isolated as they should be.
You need to use the proper bundler and gem. If you're using ChefDK, then it includes its own bundler and gem executables. They should be inside the /opt/chefdk directory, I believe under /opt/chefdk/embedded (I don't use chefdk, so I can be 100% sure of that).
To work 100% inside that ruby install, you need to ensure that the chefdk binaries are in your path before the other ruby related binaries. You can verify that with which ruby which gem and which bundle.
All that said, you really SHOULDN'T be messing with the ruby install for chefdk. It's embedded for a reason, so that you don't accidentally mess it up. I'd suggest you stick with the system ruby for your own work, and let Chef handle its ruby.
From Bundler docs:
--path: Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). Bundler will remember this value for future installs on
this machine
Your bundler may have cached a --path specified install command.
Try:
bundle install --system
This will tell bundler to use the system installed gems as opposed to downloading new gem copies to a folder specific gem collection.

How to install (ruby) bundler when bundler is broken

After adding
gem "ransack", :git => "git://github.com/ernie/ransack.git"
to my gemfile, I now get the error message :
git://github.com/ernie/ransack.git (at master) is not checked out. Please run `bundle install` (Bundler::GitError)
for any rails <>, bundle, or gem command.
This is with bundler version 1.0.21.
I see there is now version 1.30 on github, but the install "instructions" on the bundler site, seem to imply that it using an existing bundler to set up the new version?
http://gembundler.com/
require "rubygems"
require "bundler"
Bundler.setup(:default, :ci)
require "nokogiri"
How can I un-install the existing (broken) bundler, and install the new version, without an older version present ?
Mike
Bundler is just a gem like any gem, and there is no need to use Bundler to install Bundler, regardless of what the instructions tell you. It's as simple as:
gem uninstall bundler
gem install bundler
If you are using RVM, there may be a little more to it than this (you may have to switch to the 'global' gemset first), but not much.

Problems with bundled gems and datamapper: conflict with muti_json version?

I have a site running with nginx/unicorn/sinatra (bundler/rvm).
After my last bundle update, I am getting an error:
in `raise_if_conflicts': Unable to activate dm-serializer-1.2.1, because multi_json-1.3.5 conflicts with multi_json (~> 1.0.3)
My Gemfile is:
source "http://rubygems.org"
gem 'unicorn'
gem 'sinatra'
gem 'datamapper'
gem 'dm-mysql-adapter'
gem 'haml'
gem 'sass'
gem 'omniauth-twitter'
Gemfile.lock does not have any reference to multi_json 1.0.3
Any ideas?
Solution was:
check Gemfile.lock to see which gem(s) bring in later version (in this case - omniauth-twitter)
Find a version of 'offender' that does not require too high version
Rollback later versions, lock to a proper version in Gemfile
In this particular case, Gemfile that works needed lines:
gem 'omniauth-twitter', '0.0.9'
gem 'multi_json', '~> 1.0.3'
One of the gems in your bundle has an older version of multi_json as a dependency it looks like. See if bundle viz tells you. You'll need to install the ruby-graphviz gem and graphviz itself if you don't have them installed already, though.
Another way to see what's up is to add multi_json to your gemfile at the version you're trying to upgrade to, then do a bundle install and see what errors come out.
This is how to fix this problem:
rvm uninstall multi_json
It will tell you that you have many versions installed, show you a list of them, and ask you which one exactly you want to uninstall.
Try the first one, if it tells you that it is used by some other gem, try the second one, and so on. Keep deleting all the unused versions until only one remains.
This is how I do it, but there may be some clearner solution. If anyone knows it, thanks for sharing it with us.

Confusion about bundler path

I opened a dedicated hosting account on DreamHost. I deployed an rails app to that. I got the following error.
You have already activated rack 1.2.1, but your Gemfile requires rack 1.3.6. Using bundle exec may solve this.
I checked the version.
$ gem list -d rack
rack (1.2.1, 1.1.0, 1.0.1, 1.0.0)
Author: Christian Neukirchen
Rubyforge: http://rubyforge.org/projects/rack
Homepage: http://rack.rubyforge.org
Installed at (1.2.1): /usr/lib/ruby/gems/1.8
(1.1.0): /usr/lib/ruby/gems/1.8
(1.0.1): /usr/lib/ruby/gems/1.8
(1.0.0): /usr/lib/ruby/gems/1.8
Rack 1.3.6 is not there. But when I checked it with "bundle show" it's already installed. (Actually I did "bundle install --deployment")
$ bundle show rack
/.../my_rails_app_root/vendor/bundle/ruby/1.8/gems/rack-1.3.6
And I have config/setup_load_paths.rb
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
begin
rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
rvm_lib_path = File.join(rvm_path, 'lib')
$LOAD_PATH.unshift rvm_lib_path
require 'rvm'
RVM.use_from_path! File.dirname(File.dirname(__FILE__))
rescue LoadError
# RVM is unavailable at this point.
raise "RVM ruby lib is currently unavailable."
end
end
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
require 'bundler/setup'
Actually I found a solution. Just "gem install rack -v 1.3.6" fixed the problem.
But why does passenger pick up system's rack gem(or user's rack gem) instead of bundle's rack gem? How do you avoid this problem?
Thanks.
Sam
Typically this is what you get when you run your app (e.g. rails server) without prefixing the command with bundle exec.
When you ran bundle install --deployment, bundler took your gems from ./vendor/cache and whacked them in ./vendor/bundle. From then on, Bundler knows where to find them, but you have to be running the app through Bundler.
Rubygems, however, does not know where these gems are, which is why they are not shown when you run the rubygems command gem list. When you installed Rack 1.3.6 using rubygems, naturally rubygems found it and your app started working.
Not using bundler to start your app lets rubygems satisfy the requirements of your app according to it's own method, and that is a fairly random - I would be quite surprised if your app is currently running all the same gem versions that you ran your tests on, for instance (Eek!)
The approach I usually take is to uninstall all the gems from the server, install a single version of rubygems and bundler, and then rely exclusively on Bundler to maintain my app's gems. The beauty of bundler is that it calculates a valid set of gems and reliably uses it.
Hope this helps!

Resources