How do I freeze gems into a Rails 3 application? - ruby-on-rails

I want to freeze a specific gem into my Rails application.
In rails 2 there was this command:
rake gems:unpack
I can't find that command in Rails 3.

So, the short answer is, you don't.
When you modify your Gemfile, and then run bundle install or bundle update, bundler handles the dependency resolution for you and determines the best (newest) versions of each gem you've required that satisfies the entire dependency chain (you won't get a new version that breaks another gem in the dependency list, etc.). You can also of course place a specific version, or a '>= 1.2.3' specification or whathaveyou in the Gemfile using the familiar syntax from the config.gem days, and bundler will make sure to satisfy that as well (or won't produce a Gemfile.lock if there is no valid resolution).
When Bundler does its business, it creates the Gemfile.lock file, which (and this is provided you use bundler alone for managing your gem on all workstations/environments/deployments) performs the same function as freezing all of the gems you've required. For free! (Check this file into version control!) If your new development intern pulls down your source on a fresh machine, it takes one bundle install and the exact same versions of the gems that you have installed are on her machine. Push to deployment, and do a bundle install --deployment there (or more likely, throw it in your Capfile), and the same gems are installed (this time into vendor/bundle, configurable). Bundler is used in Rails 3 to manage loading all of the gems, so wherever you've told bundler to install them (whatever your normal gem install location is by default, or BUNDLE_PATH (which is recorded in .bundle/config if you install with bundle install --path=foo otherwise), bundler will load the right ones, even when they differ from system gems.
You don't need to unpack the gems and check them in to your app, because it doesn't matter: you're guaranteeing the same versions are being called regardless of where they are installed, which will likely vary from machine to machine anyways (.bundle/ should not be checked in to the repo) - so why stick another 60-80 MB of files into your repo that you won't ever be changing or using? (incidentally, this is why I wouldn't recommend a bundle install --path=vendor/gems like nfm suggested - it's not necessarily wrong, there's just no benefit to it over the normal bundler workflow, and now your repo size just ballooned up).

DO NOT USE THE "RECOMMENDED" ANSWER BY NFM!
Instead, review the Bundler site, particularly the page on deployments:
http://gembundler.com/deploying.html
The short summary is to use specific versions in your Gemfile and run bundle install --deployment on each target system where you need the exact gem versions.
Using the --path option will install the gems, but it's not really what you want to do. As Matt Enright said, you just bloat your SCM with stuff that bundler can handle smartly on each target environment.

I haven't had to do this yet, but I believe it's all handled by bundler.
When you create a new rails3 app, the rails dependencies are put into your Gemfile. You can run bundle install to install them. By default, they are installed into your BUNDLE_PATH.
If you want to install them within your app, you can specify where: bundle install vendor/gems.

I had to do this for typus gem deployment on Heroku as you can't run a heroku rails generate typus on Heroku given it's a read only file system. I didn't want ALL gems put into my app, just the one that was causing me grief. Here are the steps that lead to success:
create directory in app_name/vendor/gems/gem_name (optional) ... in my case /app_name/vendor/gems/typus
add the following to gemfile (this tells bundle where to find and put the gem source):
gem 'typus', :git => 'https://github.com/fesplugas/typus.git', :path => "vendor/gems/typus"
then from within your app directory (this installs the gem into your app):
'gem unpack typus --target vendor/gems/typus'
then bundle install
then .. in my case... commit and push to repository and then deploy up to heroku... you may have to run a heroku rake db:migrate

Assuming you already have bundler gem installed:
$ bundle lock
$ git add Gemfile.lock

You can bundle install on dreamhost without any issues. If you are on shared the environment is already setup to store them locally in your home directory. If you are on a VPS or Dedicated you can run bundle install as root or just add this to your .bash_profile
export GEM_HOME=$HOME/.gems
export GEM_PATH=$GEM_HOME:/usr/lib/ruby/gems/1.8

I think what you are looking for is
bundle package
checkout the man pages here:
http://gembundler.com/man/bundle-package.1.html

I second the answer by tsega (updated by coreyward). "bundle package" is the generic answer.
The poster didn't ask WHETHER to freeze his gems. He wanted to know HOW. Answers like "Just don't do it" aren't helpful at all. Yes, it turned out his specific problem was a little different than that, but while "bundle package" might have been overkill it still solves the problem.
I have worked on a lot of systems, and on some you just don't have full access. Installing gems on some systems just isn't an option. So unless you package them, in general you're screwed. There are different workarounds for different hosts and systems, but none for some.

Pod - If you need to modify the gem, the best practice to do this would be forking the project, making the change, then using the 'git' flag in bundler:
git 'some_gem', :git => 'git://github.com/me/my_forked_some_gem.git'
This way you'll be notified when the gem is updated.

The command that you want is bundle package which just unpacks the gems and dependencies at vendor/cache folder.
But just a notice, the :git => .... kind of gems wont get packaged. You have to hack a way out for :git => ... related gems to get packed.

Cleaner instructions for the gem unpack and :path => option:
https://stackoverflow.com/a/8913286/555187

A lot of comments are somewhat saying that it's not useful to use the bundle install --path vendor/gems, but those people who are using Dreamhost, it should note that you cannot use bundle install in Dreamhost.
The solution is to get all the gems into the vendor folder and upload the whole thing to the Dreamhost directory.
There are other solutions to turn around this, but it's much more complicated to do.

Well I have to modify slightly one of the gems I need. So I need to keep it inside my Repo. So what NFM mentioned is what I probably need.

Related

CircleCI says Your bundle could not be found in any of the sources listed in your Gemfile

CircleCI install dependencies error:
Your bundle is locked to my_cool_gem (0.7.2), but that version could not be
found in any of the sources listed in your Gemfile. If you haven't changed
sources, that means the author of my_cool_gem (0.7.2) has removed it. You'll
need to update your bundle to a version other than my_cool_gem (0.7.2) that
hasn't been removed in order to install.
Screenshot of CircleCI output:
CircleCI can't find a gem that I published to GitHub Packages, yet I have no such problem in local development.
I have qualifying versions of RubyGems and Bundler, as per GitHub's docs - https://docs.github.com/en/free-pro-team#latest/packages/guides/configuring-rubygems-for-use-with-github-packages - and I believe I have followed the instructions to publish and use said published gems... and, again, usage works locally but fails in CircleCI...
RubyGems version:
-bash> gem --version
3.0.9
Bundler version:
-bash> bundle --version
Bundler version 1.17.3
Gemfile:
source 'https://rubygems.org'
source 'https://rubygems.pkg.github.com/my_cool_org'
gem 'my_cool_gem', '0.7.2'
Note that I have also tried:
source 'https://rubygems.org'
source 'https://rubygems.pkg.github.com/my_cool_org'
source 'https://rubygems.pkg.github.com/my_cool_org' do
gem 'my_cool_gem', '0.7.2'
end
Try running bundle update my_cool_gem if it modifies Gemfile.lock that should fix it.
Have you verified that it's actually still available at the source? I know you said it works locally, but that could be because of local cached versions of the gem. Bundle won't try to install something that's already there.
You might be able to verify this by uninstalling it locally and running bundle install again.
Ensure that you've correctly set the environment variable for authenticating with rubygems.pkg.github.com.
(Though the variable may be set, the value may be incorrect - as was the case for me.)
Interesting, sounds like a image bug. What happens if you try to list all available versions of your gem? gem search ^gem_name$ --all?
Have you tried to force update beforehand? sudo gem update --system
For me, the problem was that access tokens was different on local machine and on CI. And the key on CI was valid, but it had no permission for specific repository containing requested gem.
Despite Github provides single registry per organization, gems are associated with company's repositories. And packages within registry will be visible or invisible depending on permissions to these repositories that access tokens have. For example, user can have access to some repositories of organization and don't have to others — if using that user's personal access token, only gems associated with permitted repositories will be visible. Others will be hidden, so the error is "that version cannot be found".
I ran into this again, and this time I could not solve it with the solution I used last time, and no other solution worked either, so instead I chose to temporarily work around the issue by placing a copy of the gem in question directly into my app (a process known as "vendoring"; see this, this, and this):
gem unpack my_cool_gem # note, I actually had to specify the version with -v 0.12.1
mkdir vendor/gems/
mv my_cool_gem-0.12.1 vendor/gems/
In Gemfile, use the :path option rather than :source:
gem 'my_cool_gem', '0.12.1', path: 'vendor/gems'
Then generate Gemfile.lock:
bundle install

Does 'bundle install' install all the required gems on my computer permanently?

I am new to rails and am learning about bundler. I understand that bundle install installs all the gems specified in the gemfile but where does it install them to?
Does it install them on my computer permanently so that they can be used by any future project?
If so doesnt this mean my computer gets filled with random gem versions and gem installs that I needed for one example project but may never use again?
By default, bundle install is going to install at the root level so all users on a computer could have access to the gems. So 'yes' it is permanent (at least not tied to your application, you can remove them whenever you want).
Take a look at the man pages for bundler. In here, you'll notice that you can specify to install to a local directory.
Install your dependencies, even gems that are already installed to your system gems, to a location other than your system's gem
repository. In this case, install them to vendor/bundle.
$ bundle install --path vendor/bundle
Further bundle commands or calls to Bundler.setup or Bundler.require
will remember this location.
This will let you install the gems to a location inside your application. So when you delete the example app, you also delete the associated gems.
Also, if you would like to see where a specific gem is installed (say you want to look at its source code), type bundle show <gemname>. This will spit out the path to that gem.
The short answer is 'yes'. The longer answer is that there are some technologies which will reduce or eliminate the problems associated with this effect.
If you install 'RVM':
https://rvm.io/
this will allow you to install multiple versions of Ruby and create individual 'gemsets'. As you enter the directory that contains your project, the ruby version and gemset settings are automatically picked up and the active Ruby version will change. This way you can keep gems separate between projects - and use several Ruby versions at once, including JRuby and other esoteric versions.
To find out where gems are stored, type:
gem environment
into your command line and look for the INSTALLATION_DIRECTORY entry in the response.

Bundler: You are trying to install in deployment mode after changing your Gemfile

I'm pretty new to bundler and capistrano, and I'm trying to use them together. When I try to deploy, I get the message:
You are trying to install in deployment mode after changing your Gemfile. Run `bundle install' elsewhere and add the updated Gemfile.lock to version control.
I don't know how to satisfy the system that's complaining, and I don't understand why the complaint is coming up because I read in the doc:
If a Gemfile.lock does exist, and you have updated your Gemfile(5),
bundler will use the dependencies in the Gemfile.lock for all gems
that you did not update, but will re-resolve the dependencies of gems
that you did update. You can find more information about this update
process below under CONSERVATIVE UPDATING.
I interpret that to mean that the Bundler can handle the fact that my Gemfile is not whatever it expected. Any help?
Specs: Ruby 1.9.3, Rails 3.2.3, Capistrano 2.12.0, Bundler 1.1.4, Windows 7, deploying to a Posix machine.
Edit: My Gemfile includes logic blocks like the following:
unless RbConfig::CONFIG['host_os'] === 'mingw32'
# gem 'a' ...
end
The error message you're getting regarding Gemfile.lock may be because your Gemfile and Gemfile.lock don't agree with each other. It sounds like you've changed something in your Gemfile since you last ran bundle install (or update). When you bundle install, it updates your Gemfile.lock with any changes you've made to Gemfile.
Make sure you run bundle install locally, and check-in to source control your newly updated Gemfile.lock after that. Then try deploying.
Edit: As recognised in the comments, a conditional in the Gemfile resulted in a valid Gemfile.lock on one platform, invalid on another. Providing a :platform flag for these platform-dependent gems in the Gemfile should solve the asymmetry.
vi .bundle/config
change the BUNDLE_FROZEN option from '1' to '0'
do "bundle install"
OR
run "bundle config"
see if the "frozen" value is true set it to false
bundle config frozen false
Watch out for global Bundler config.
I had a global config on my dev environment in ~/.bundle/config that I did not have in my CI / Production environment that caused the Gemfile.lock that was generated in my dev environment to be different than the one in my CI / Production environment.
In my case I was setting github.https to true in my dev environment but had no such config in my CI / Production environment. This caused the two Gemfile.lock files to be different.
When you see the following...
$ bundle install
You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.
If this is a development machine, remove the Gemfile freeze
by running `bundle install --no-deployment`.
You have added to the Gemfile:
* source: rubygems repository https://rubygems.org/
* rails (~> 3.2)
. . .
... Then, the problem is most likely that you have outdated .gem files in your vendor/cache directory.
Perhaps, you previously ran $bundle install --deployment which put some "outdated" .gem files in the cache?
In any case, you can get past this error by running: bundle install --no-deployment
That's one of the many great things about Rails... the error messages often tell you exactly what to do to fix the problem.
My specific problem was related to what reported by #JoshPinter, i.e. dev-vs-deploy host discrepancies in the protocol used by bundler to retrieve gems from github.
To make a long story short, all I had to was modify the following Gemfile entry...
gem 'activeadmin', github: 'activeadmin'
...to this secure syntax (see reference):
gem 'activeadmin', git: 'https://github.com/activeadmin/activeadmin.git'
And my deployments are back to normal.
I don't care. This is what I did. It fixed it.
rm -rf .bundle
rm -rf Gemfile.lock
bundle install
The solution for me was slightly different than the others listed here. I was trying to upgrade from sidekiq to sidekiq-pro (which requires bundler 1.7.12+), but I kept getting the "You are trying to install in deployment mode after changing your Gemfile" message from travis-ci
Inspecting the console output of travis-ci revealed that an older version of bundler was being used.
In my case, I had to edit the travis.yml file to add:
before_install:
- gem update bundler
This forced travis-ci to use the latest version of bundler, and made the error message go away.
rm -fr .bundle
Fixed the problem for me.
Another cause of the error:
This is a bit foolish, but i'm sure someone else will make the same mistake.
For Rails 4 Heroku added the gem rails_12factor. If you were using it before they added it, then you'll have these two gems:
gem 'rails_log_stdout', github: 'heroku/rails_log_stdout'
gem 'rails3_serve_static_assets', github: 'heroku/rails3_serve_static_assets'
You have to remove them when you add the new one. (they're included). I think you can get away with it until you touch them lines in your gem file, then Heroku notices the duplication and cries out with the above error.
good luck with Rails 4.
After this command, you can do your normal bundle install again:
bundle install --no-deployment
I ran into something similar before. One way to fix it, I think, but may take more space on your server than you want, is to run
bundle install --deployment
and then try to deploy. This does something like install all of your gems into the vendor folder, which I believe is generally good to avoid... but will still probably work. My app used to behave like this, my solution was removing exact versions to download from in my Gemfile, and then rebundling and deploying.
gem 'rails_admin', :git => 'git://github.com/sferik/rails_admin.git', :branch => 'master'
to
gem 'rails_admin'
Or you can do what it suggests, and Git your project off the production server onto a local machine, bundle it, and then repush onto your server. This solution might not be 100% correct but some of it worked for me... just thought I'd share. Goodluck
In our case we were using a feature that wasn't available in an old version of bundler which ran on our production machine. Therefore it was enough to upgrade bundler, i.e. do a gem update bundler.
This might be a dangerous idea, but if absolutely must test something in a production deploy environment, you can edit the .bundle/config file
# This value is normally '1'
# Set it to '0'
BUNDLE_FROZEN: '0'
Now invoke bundle, in my case I needed to update a specific gem, so this my command
RAILS_ENV=production bundle update <whatever gem>
You should probably change it back after the update, so things work like you expect, afterwards. Again, this is probably unsupported, and YMMV
This issue can be related to submodules pointing to old versions of code. For me, I resolved this issue by updating my submodules
If you have submodules, try running:
git submodule update --init
bundle install
The error message for the command bundle install in windows 10 (rails v-7) was like
You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
If this is a development machine, remove the C:/Users/friends/Gemfile freeze
by running `bundle config unset deployment`.
The dependencies in your gemfile changed
You have added to the Gemfile:
* pg
You have deleted from the Gemfile:
* sqlite3 (~> 1.4)
So I did exactly the error message asked me to do. Ran the following command
bundle config unset deployment
And then I again ran `bundle install and then it worked
I ran into this deploying a Nesta app after some gem updates. What worked for me was to delete the Gemfile.lock, run bundle install to re-generate it, and deploy again.
I ran into a similar issue however I did both bundle install and bundle update and Heroku still rejected my push.
I fixed the issue by just deleting Gemfile.lock and then running bundle install again. I then added, committed, and pushed that to my git repo. After that I had no problem pushing to Heroku.
for heroku, you don't have to change the syntax in the Gemfile. you can just add BUNDLE_GITHUB__HTTPS (note the double underscore) as an environment variable and set it to true (in your heroku app's dashboard under the Settings tab in the Config Vars section). this will switch the protocol from git:// to https:// for all such requests.
I had the error message when attempting push to Heroku. I found the following solution fixed.
Git pull origin master
Git status
Git commit
Git push origin master
Git push heroku master
I read a dozen solutions on different resources but didn't find exactly what could help me in this situation
So I did find a solution. Exactly saying i read the error message attentively and there was a sollution: Run bundle install elsewhere. "Elsewhere" was my Cloud9 where i developed my app. So my steps
copy Gemfile and Gemfile.lock from server to local machine with rsync command
insert these two files into my RoR project (i used Cloud9)
open Gemfile and make changes that i want. In my case i added gem 'thin'
in terminal cd to my app on Cloud9 and run bundle install. in this case you will have a changed version of Gemfile.lock
copy new Gemfile and Gemfile.lock on server using rsync
cd to my app folder and again run bundle install --deployment --without development test
DONE! Wish GOOD luck for all!
As of the time of this writing Bundler support for capistrano defaults to "deployment: true", per
https://github.com/capistrano/bundler
So as opposed to trying to modify the bundle by hand after bundler [via capistrano] has laid it down, you may be able to solve the problem permanently by adding this to your deploy.rb or other Capistrano config file [you can do it just for one stage file as well if necessary]:
set :bundle_config, { deployment: false }
and then deploying again.
You will then notice in the "cap" output the following line [note I am using rvm here but you may not be]
.../rvm ruby-2.7.6#... do bundle config --local deployment false
Why did this stop working all of a sudden?
This is the $1M question, I never had to mess with this, but once I got to an Ubuntu 20.04.05 machine, suddenly, yes. Same cap files, same ruby version, same rails version, same OS version except the minor number.
Did it work?
Did this work for you? Leave me a comment and let me know.

Rails 3 "bundle install" in Capistrano deploy -- but how to clean up?

After a long overdue reading of the bunder documents, I pretty much understand why it's a great thing compared to manual gem install.
But this came to me (and others) only recently, and now we have a hybrid environment. Our development machines are mostly fine. But when we deploy to production, Bundler tells capistrano to put the gems in shared/bundle/gems, which makes sense. But we still have manually installed gems in the normal .rvm location.
So now we know not to use "gem install" on production, but we're dealing with version mismatches when we run Rake tasks directly. We can use "bundle exec rake foo:bar" to force the correct behavior, I think. But for now we have a bunch of outdated gems:
Outdated gems installed by Bundler, and
Gems we manually installed using gem install
I would like to get things pristine. Is there any reason I shouldn't use gem cleanup?
Hope this isn't too convoluted :-)
Thanks in advance.
gem cleanup will keep the latest version of all gems, and remove older versions. What I think you want is this:
(Optional) create an RVM gemset for your project. (I like to do this; some people rely entirely on Bundler, which also works.)
Make sure all your top-level dependencies are specified in your Gemfile.
Remove all gems (rvm gemset empty may be helpful) except Bundler.
bundle install
Run everything with bundle exec from now on.

I don't completely understand the gemfile in a rails application

What is the difference between installing a gem from the command line
sudo gem install gem-name
and writing your gem into the Gemfile and running bundle install?
I think the problem is that I don't understand the exact purpose of the Gemfile. So far it seems like it is a place to list all of the gems that your app is dependent on.
Installing a gem via:
sudo gem install gem-name
is going to install that gem system wide.
Whereas installing them via the Gemfile is specific for your rails app(to keep track of dependencies, version, app portability etc).
The best source of the whats and whys about Bundler, is probably this page:
http://gembundler.com/rationale.html
That page has great examples and explanation about why Bundler is useful and in some cases, necessary.
I always thought you write all gems that your app is dependent on in it, and then if you want to port your application somewhere else, you can run the bundle install and it'll grab the gems you need for you so you don't manually have to do it.
This might clear things up, I quote:
'It holds information about all the project dependencies so that you don't need to struggle to figure out what gems you need to install.'
http://blog.despo.me/42762318

Resources