should bundle exec find a global gem? - ruby-on-rails

visual studio code launch configuration (not terrible important) tries to start rdebug-ide via
bundle exec rdebug-ide
This works only if I add the gems to the Gemfile.
Is bundle exec supposed to only find binaries included in the Gemfiles or should those installed globally, e.g. gem install rdebug-ide, also be accessible from bundle exec?
So this works:
> rdebug-ide
Using ruby-debug-base 0.2.2 ...
but this doesn't
> bundle exec rdebug-ide
Gem::Exception: can't find executable rdebug-ide for gem ruby-debug-ide. ruby-debug-ide is not currently included in the bundle, perhaps you meant to add it to your Gemfile?
and even this works!
> bundle exec ls
Gemfile app ...
Extra info: I'm using rbenv, perhaps that affects bundler behavior somehow
UPDATE
#tadman pointed out that bundle exec is altering the path. But as I would have expected it seems to be extending it, not removing anything
$ diff <(gem env) <(bundle exec gem env)
24a25
> - /Users/eng/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/bin
$ which rdebug-ide
/Users/eng/.rbenv/shims/rdebug-ide
$ bundle exec rdebug-ide
bundler: failed to load command: rdebug-ide
(/Users/eng/.rbenv/versions/2.5.3/bin/rdebug-ide)
Gem::Exception: can't find executable rdebug-ide for gem ruby-debug-ide. ruby-debug-ide is not currently included in the bundle, perhaps you meant to add it to your Gemfile?
furthermore the path is in there:
$ bundle exec gem env | grep $(dirname $(which rdebug-ide))
- /Users/eng/.rbenv/shims
I'm tending to think that rbenv is somehow messing things up.

bundle exec does a number of things, primarily changing the Gem environment, but most importantly it alters your search PATH for executables.
Many, like ls which exist outside of Ruby will still be present, but gem executables may be knocked out if not included in the Gemfile.
Check with:
bundle exec gem env
And compare with:
gem env
You'll see a number of changes in the "SHELL PATH" section.

Related

how to avoid installing rails as a system gem by using bundler and expect

I'm trying to make a new rails application with a intent not to install gems as system gem as possible.
At first I installed bundler as system gem, made a Gemfile which specified only rails and executed 'bundle install'. (In my opinion, bundler is OK to be a system gem...)
mkdir -p /opt/rails/rails_app
cd /opt/rails/rails_app
gem install bundler
bundle init
cp Gemfile /tmp
sed 's/#gem rails/gem rails/' /tmp/Gemfile > Gemfile
bundle config build.nokogiri --use-system-libraries
bundle install --path vendor/bundle
Rails was installed as a 'local gem' which is limitted within /opt/rails/rails_app.
Then I tried to make a rails application by 'rails new'.
bundle exec rails new . --skip-bundle
This caused replacing the Gemfile, so a message was shown like this.
Overwrite /opt/rails/rails_app/Gemfile? (enter "h" for help) [Ynaqdh]
Usually what should be done is only type 'y'. However, this time, I want to do that automatically for making a vagrant's provision script.
So I tried expect but it never worked. All results were either timeout or syntax error:
expect -c "
spawn bundle exec rails new . --skip-bundle --quiet
expect \"Overwrite /opt/rails/rails_app/Gemfile? (enter \"h\" for help) \[Ynaqdh\] \"
send \"y\r\"
"
I couldn't find where is wrong in this code and other solutions than using expect.
It looks like there is a skip_gemfile option in the rails generator
You can use bundle install --path [directory] to install you gems locally inside your app. Typicall you would use './vendor/bundle' as your directory.

How to delete a gem so that I don't need to prepend bundle exec for rails commands?

If I try to run tests I get
Gem::LoadError: You have already activated jruby-openssl 0.9.5, but your Gemfile requires jruby-openssl 0.8.5. Prepending bundle exec to your command may solve this.
I can do as indicated and prepend bundle exec to get around this.
This is happening because I have a newer version of the gem in another project.
However I am no longer using the other application with the newer version of the gem, so I was wondering:
How can I actually remove the newer version so I don't have to bundle exec before my rails commands?
You can delete a gem (or a specific version of a gem) by running
gem uninstall <gem_name>
If there's multiple versions then a prompt will ask which version to remove.
Use gem uninstall with the -v switch to specify a version to uninstall:
gem uninstall jruby-openssl -v 0.9.5
Depending on your OS and shell, you could create an alias or function for the command (I’m guessing this is using Rake).
For example I have this in my .bashrc
function bake {
bundle exec rake "$#"
}
So now I can type bake whatever and the command that is run is bundle exec rake whatever.
This usually happens when you are 'polluting' the global gemset using it for different projects.
A good way to isolate gemsets is to use rvm. Once installed, you can create a file per project named .ruby-version with a single line on it that identifies the gemset with the syntax <ruby version>#<your project>. From the console:
$> echo "2.1#myproject" > .ruby-version
$> cd .
This will create a gemset for your project and everytime you enter the root directory, the gemset will be specific to this project. Then you could have different gem versions for different projects and run rake (or any other command) just fine without messing dependencies.

How do I check that RVM + Bundler are working correctly (and that I can avoid "bundle exec")? I'm slightly confused over wording in the docs

I'm following this Rails tutorial section and this RVM doc page . My installation is all brand new (RVM 1.17.3), so, if I understand the tutorial and the RVM docs correctly:
RVM and Bundler should be integrated by default and I don't have to configure anything. (No need to run bundle --bunstubs?)
I don't need to type "bundle exec"
Did I read that right?
I don't see a bundler_stubs/ or bin/ directory in my application.
Is there a way for me to check that it's set up properly so I can be sure that bundle exec is not necessary?
edit:
Running which yields the following:
$ bundle show rspec
$ /home/{username}/.rvm/gems/ruby-1.9.3-p327#tutorial/gems/rspec-2.11.0
$ which rspec
$ /home/{username}/.rvm/gems/ruby-1.9.3-p327#tutorial/bin/rspec
Which seems to imply that I should keep using bundle exec because they are not the same?
RVM by default installs gem https://github.com/mpapis/rubygems-bundler which detects if you are in context of Gemfile and automatically loads bundler if required, it is equivalent to manually typing bundle exec.
bundle exec is a bundle command to execute a script in the context of the current bundle (the one from your directory's Gemfile). rspec filename.rb is the script.
so bundle exec bundle exec rspec filename.rb executes the rake script with the command rspec filename.rb in the context of the current bundle.
As to the "why?" I'll quote from the bundler documentation:
In some cases, running executables without bundle exec may work,
if the executable happens to be installed in your system and does not pull in any gems that conflict with your bundle. However, this is unreliable and is the source of considerable pain. Even if it looks like it works, it may not work in the future or on another machine.
See http://gembundler.com/man/bundle-exec.1.html for more info.

To bundle exec or not to bundle exec

I have created a gem that provides an executable. Now I'd like the users of my gem to being able to use the executable independently from their setup especially regarding RVM and Bundler. Some users install the gem globally:
gem install foobar
Some users install it inside projects using Bundler:
echo "gem 'foobar'" > Gemfile && bundle
Some users have a Gemset per projects, others do not.
My Problem now is, that my gem creates a git hook that looks actually like that:
#!/bin/sh
bundle exec foobar -dostuff
That approach does not work for users, who did not install my gem using Bundler. If I changed that to:
#!/bin/sh
foobar -dostuff
some users have trouble, because the executable can not be found, or the "wrong" executable is executed.
Is there any way to clean up this "bundle exec" mess and provide a behavior of the executable that works for all users?
Regards
Felix
This script should help - https://github.com/gma/bundler-exec/blob/master/bundler-exec.sh
Read more on it here - http://effectif.com/ruby/automating-bundle-exec

What does bundle exec rake mean?

What does bundle exec rake db:migrate mean? Or just bundle exec rake <command> in general?
I understand that bundle takes care of maintaining things in the Gemfile. I know what the word "exec" means. I understand that rake maintains all the different scripty things you can do, and I know that db:migrate is one of those. I just don't know what all these words are doing together. Why should bundle be used to execute rake to execute a database migrate?
bundle exec is a Bundler command to execute a script in the context of the current bundle (the one from your directory's Gemfile). rake db:migrate is the script where db is the namespace and migrate is the task name defined.
So bundle exec rake db:migrate executes the rake script with the command db:migrate in the context of the current bundle.
As to the "why?" I'll quote from the bundler page:
In some cases, running executables without bundle exec may work, if the executable happens to be installed in your system and does not pull in any gems that conflict with your bundle.
However, this is unreliable and is the source of considerable pain. Even if it looks like it works, it may not work in the future or on another machine.
You're running bundle exec on a program. The program's creators wrote it when certain versions of gems were available. The program Gemfile specifies the versions of the gems the creators decided to use. That is, the script was made to run correctly against these gem versions.
Your system-wide Gemfile may differ from this Gemfile. You may have newer or older gems with which this script doesn't play nice. This difference in versions can give you weird errors.
bundle exec helps you avoid these errors. It executes the script using the gems specified in the script's Gemfile rather than the systemwide Gemfile. It executes the certain gem versions with the magic of shell aliases.
See more on the man page.
Here's an example Gemfile:
source 'http://rubygems.org'
gem 'rails', '2.8.3'
Here, bundle exec would execute the script using rails version 2.8.3 and not some other version you may have installed system-wide.
This comes up a lot when your gemfile.lock has different versions of the gems installed on your machine. You may get a warning after running rake (or rspec or others) such as:
You have already activated rake 10.3.1, but your Gemfile requires rake 10.1.0. Prepending "bundle exec" to your command may solve this.
Prepending bundle exec tells the bundler to execute this command regardless of the version differential. There isn't always an issue, however, you might run into problems.
Fortunately, there is a gem that solves this: rubygems-bundler.
$ gem install rubygems-bundler
$ $ gem regenerate_binstubs
Then try your rake, rspec, or whatever again.
It should probably be mentioned, that there are ways to omit bundle exec (they are all stated in chapter 3.6.1 of Michael Hartls Ruby on Rails Tutorial book).
The simplest is to just use a sufficiently up-to-date version of RVM (>= 1.11.x).
If you're restricted to an earlier version of RVM, you can always use this method also mentioned by calasyr:
$ rvm get head && rvm reload
$ chmod +x $rvm_path/hooks/after_cd_bundler
$ bundle install --binstubs=./bundler_stubs
The bundler_stubs directory should then also be added to the .gitignore file.
A third option is to use the rubygems-bundler gem if you're not using RVM:
$ gem install rubygems-bundler
$ gem regenerate_binstubs
When you directly run the rake task or execute any binary file of a gem, there is no guarantee that the command will behave as expected. Because it might happen that you already have the same gem installed on your system which have a version say 1.0 but in your project you have higher version say 2.0. In this case you can not predict which one will be used.
To enforce the desired gem version you take the help of bundle exec command which would execute the binary in context of current bundle. That means when you use bundle exec, bundler checks the gem version configured for the current project and use that to perform the task.
I have also written a post about it which also shows how we can avoid using it using bin stubs.
I have not used bundle exec much, but am setting it up now.
I have had instances where the wrong rake was used and much time wasted tracking down the problem. This helps you avoid that.
Here's how to set up RVM so you can use bundle exec by default within a specific project directory:
https://thoughtbot.com/blog/use-bundlers-binstubs
It means use rake that bundler is aware of and is part of your Gemfile over any rake that bundler is not aware of and run the db:migrate task.

Resources