Update gem on staging server only - ruby

I want to update one of my gems on staging server ONLY. So, I'm running
bundle update gemname
or
bundle install
but then I got error:
You have modified your Gemfile in development but did not check the resulting snapshot (Gemfile.lock) into version control
The problem is that I can't do it locally and I can't push it into git repository. Any ideas how to solve it?

OK, my problem was specific and quite rare, because I could't deploy app with new features due to situation with my client. Maybe it sounds awful, but at first I got to locally update my Gemfile, run bundle install, manually copy Gemfile.lock to my server and after all I could update gems as I want to. It works at now and when I will be allowed to deploy whole app code with capistrano, everything will be fine.

You can create groups in your Gemfile like this in your case:
group :staging do
gem 'gem_name', 'gem_version'
end
Only put the gems that you want to use in that specific environment.
Hope this helps :)

Related

IMPORTANT: Remember to use the included executable `certifed-update` regularly to keep your certificate bundle up to date

$ gem install bundler
gives me (at the end of the successful install):
Post-install message from certified:
IMPORTANT: Remember to use the included executable `certifed-update` regularly to keep your certificate bundle up to date.
I can't see how I'm going to remember to keep this executable indefinitely up to date. Any suggestions?
There is a typo in the message: certifed-update does not exist, it's certified-update (notice the missing "i"). It's strange as this typo is fixed in latest gem code (maybe the author forgot to publish a new version, who knows)
You can run this tool manually with:
bundle exec certified-update
Which yields this message:
Updating ca-bundle from
https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt
Certificate bundle updated. Remember to do this regularly!
In order to remember to update the certificates you can configure a periodic reminder in your calendar, or you can setup a cron job or similar to make it automatically ;-)
It seems you're using this gem and it's getting run somehow after gem install bundler. Try deleting it via gem uninstall certified and rerun gem install bundler.

Where are "asset group" gems installed?

I have some gems that are only used for the asset pipeline. One example is:
gem 'jquery-datatables-rails', github: 'rweng/jquery-datatables-rails'
Unfortunately, I can not find exactly where this gem is installed. "gem list --local" does not even show it.
I need to fix it, because I am trying to use Bootstrap styling in datatables, which is allowed in the latest version. But the version of datatables included with the gem is old.
Does anybody know where these gems go? I am very, very confused by the asset pipeline.
I such cases, I fork the project on github and make my changes, and adjust my Gemfiles accordingly. This also makes it reuseable in different projects.
The asset pipeline and Bundler grouping has nothing to do with where gems are installed on your system. You can always run bundle open gemname to open the source of a Gem in your $EDITOR and make quick changes (i.e. for debugging). If you want to actually include changes in a release, though, you are going to want to fork the Gem and make your changes there, then specify the git path in your Gemfile.
As a side note, make sure you run bundle install (or really, just bundle) after making changes to your Gemfile to ensure the Gems all get installed.

Should Gemfile.lock be included in .gitignore?

I'm sort of new to bundler and the files it generates. I have a copy of a git repo from GitHub that is being contributed to by many people so I was surprised to find that bundler created a file that didn't exist in the repo and wasn't in the .gitignore list.
Since I have forked it, I know adding it to the repo won't break anything for the main repo, but if I do a pull request, will it cause a problem?
Should Gemfile.lock be included in the repository?
Update for 2022 from TrinitronX
Fast-forward to 2021 and now Bundler docs [web archive] now say to commit the Gemfile.lock inside a gem... ¯_(ツ)_/¯ I guess it makes sense for developers and ease of use when starting on a project. However, now CI jobs need to be sure to remove any stray Gemfile.lock files to test against other versions.
Legacy answer ~2010
Assuming you're not writing a rubygem, Gemfile.lock should be in your repository. It's used as a snapshot of all your required gems and their dependencies. This way bundler doesn't have to recalculate all the gem dependencies each time you deploy, etc.
From cowboycoded's comment below:
If you are working on a gem, then DO NOT check in your Gemfile.lock. If you are working on a Rails app, then DO check in your Gemfile.lock.
Here's a nice article explaining what the lock file is.
The real problem happens when you are working on an open-source Rails app that needs to have a configurable database adapter. I'm developing the Rails 3 branch of Fat Free CRM.
My preference is postgres, but we want the default database to be mysql2.
In this case, Gemfile.lock still needs be checked in with the default set of gems, but I need to ignore changes that I have made to it on my machine. To accomplish this, I run:
git update-index --assume-unchanged Gemfile.lock
and to reverse:
git update-index --no-assume-unchanged Gemfile.lock
It is also useful to include something like the following code in your Gemfile. This loads the appropriate database adapter gem, based on your database.yml.
# Loads the database adapter gem based on config/database.yml (Default: mysql2)
# -----------------------------------------------------------------------------
db_gems = {"mysql2" => ["mysql2", ">= 0.2.6"],
"postgresql" => ["pg", ">= 0.9.0"],
"sqlite3" => ["sqlite3"]}
adapter = if File.exists?(db_config = File.join(File.dirname(__FILE__),"config","database.yml"))
db = YAML.load_file(db_config)
# Fetch the first configured adapter from config/database.yml
(db["production"] || db["development"] || db["test"])["adapter"]
else
"mysql2"
end
gem *db_gems[adapter]
# -----------------------------------------------------------------------------
I can't say if this is an established best practice or not, but it works well for me.
My workmates and I have different Gemfile.lock, because we use different platforms, windows and mac, and our server is linux.
We decide to remove Gemfile.lock in repo and create Gemfile.lock.server in git repo, just like database.yml. Then before deploy it on server, we copy Gemfile.lock.server to Gemfile.lock on server using cap deploy hook
Agreeing with r-dub, keep it in source control, but to me, the real benefit is this:
collaboration in identical environments (disregarding the windohs and linux/mac stuff). Before Gemfile.lock, the next dude to install the project might see all kinds of confusing errors, blaming himself, but he was just that lucky guy getting the next version of super gem, breaking existing dependencies.
Worse, this happened on the servers, getting untested version unless being disciplined and install exact version. Gemfile.lock makes this explicit, and it will explicitly tell you that your versions are different.
Note: remember to group stuff, as :development and :test
Simple answer in the year 2021:
Gemfile.lock should be in the version control also for Rubygems. The accepted answer is now 11 years old.
Some reasoning here (cherry-picked from comments):
#josevalim https://github.com/heartcombo/devise/pull/3147#issuecomment-52193788
The Gemfile.lock should stay in the repository because contributors and developers should be able to fork the project and run it using versions that are guaranteed to work.
#rafaelfranca https://github.com/rails/rails/pull/18951#issuecomment-74888396
I don't think it is a good idea to ignore the lock file even for plugins.
This mean that a "git clone; bundle; rake test" sequence is not guarantee to be passing because one of yours dozens of dependencies were upgraded and made your code break. Also, as #chancancode said, it make a lot harder to bisect.
Also Rails has Gemfile.lock in git:
https://github.com/rails/rails/commit/0ad6d27643057f2eccfe8351409a75a6d1bbb9d0
The Bundler docs address this question as well:
ORIGINAL: http://gembundler.com/v1.3/rationale.html
EDIT: http://web.archive.org/web/20160309170442/http://bundler.io/v1.3/rationale.html
See the section called "Checking Your Code into Version Control":
After developing your application for a while, check in the
application together with the Gemfile and Gemfile.lock snapshot. Now,
your repository has a record of the exact versions of all of the gems
that you used the last time you know for sure that the application
worked. Keep in mind that while your Gemfile lists only three gems
(with varying degrees of version strictness), your application depends
on dozens of gems, once you take into consideration all of the
implicit requirements of the gems you depend on.
This is important: the Gemfile.lock makes your application a single
package of both your own code and the third-party code it ran the last
time you know for sure that everything worked. Specifying exact
versions of the third-party code you depend on in your Gemfile would
not provide the same guarantee, because gems usually declare a range
of versions for their dependencies.
The next time you run bundle install on the same machine, bundler will
see that it already has all of the dependencies you need, and skip the
installation process.
Do not check in the .bundle directory, or any of the files inside it.
Those files are specific to each particular machine, and are used to
persist installation options between runs of the bundle install
command.
If you have run bundle pack, the gems (although not the git gems)
required by your bundle will be downloaded into vendor/cache. Bundler
can run without connecting to the internet (or the RubyGems server) if
all the gems you need are present in that folder and checked in to
your source control. This is an optional step, and not recommended,
due to the increase in size of your source control repository.
No Gemfile.lock means:
new contributors cannot run tests because weird things fail, so they won't contribute or get failing PRs ... bad first experience.
you cannot go back to a x year old project and fix a bug without having to update/rewrite the project if you lost your local Gemfile.lock
-> Always check in Gemfile.lock, make travis delete it if you want to be extra thorough https://grosser.it/2015/08/14/check-in-your-gemfile-lock/
A little late to the party, but answers still took me time and foreign reads to understand this problem. So I want to summarize what I have find out about the Gemfile.lock.
When you are building a Rails App, you are using certain versions of gems in your local machine. If you want to avoid errors in the production mode and other branches, you have to use that one Gemfile.lock file everywhere and tell bundler to bundle for rebuilding gems every time it changes.
If Gemfile.lock has changed on your production machine and Git doesn't let you git pull, you should write git reset --hard to avoid that file change and write git pull again.
The other answers here are correct: Yes, your Ruby app (not your Ruby gem) should include Gemfile.lock in the repo. To expand on why it should do this, read on:
I was under the mistaken notion that each env (development, test, staging, prod...) each did a bundle install to build their own Gemfile.lock. My assumption was based on the fact that Gemfile.lock does not contain any grouping data, such as :test, :prod, etc. This assumption was wrong, as I found out in a painful local problem.
Upon closer investigation, I was confused why my Jenkins build showed fetching a particular gem (ffaker, FWIW) successfully, but when the app loaded and required ffaker, it said file not found. WTF?
A little more investigation and experimenting showed what the two files do:
First it uses Gemfile.lock to go fetch all the gems, even those that won't be used in this particular env. Then it uses Gemfile to choose which of those fetched gems to actually use in this env.
So, even though it fetched the gem in the first step based on Gemfile.lock, it did NOT include in my :test environment, based on the groups in Gemfile.
The fix (in my case) was to move gem 'ffaker' from the :development group to the main group, so all env's could use it. (Or, add it only to :development, :test, as appropriate)

How to customize Gemfile per developer?

There is a common pattern:
there are many developers working on one project and the Gemfile(.lock) is shared via SCM. But what if some developers want to use different tools for testing and development? How to do it?
The problem is, that when you put conditional sections to your Gemfile, also the Gemfile.lock will be different for each developer and therefor you'll get conflict each time you commit to SCM.
Is there some simple, widely acknowledged solution?
I like to have this in my Gemfile:
local_gemfile = File.dirname(__FILE__) + "/Gemfile.local"
if File.file?(local_gemfile)
require local_gemfile
end
I also have Gemfile.local and Gemfile.lock in gitignore. I know I'm not "supposed to", but I don't think the caveats (such as the ones you mention in your question) are worth it.
UPDATE for Bundler 1.0.10 as of March 3, 2011
local_gemfile = File.dirname(__FILE__) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
end
I had to use this with Rails 3 and Bundler 1.0.10.
If you check in something that depends on a gem that gem should be in the gemfile. If the code in the repository does not depend on a gem, there's no need to have it in the gemfile. So, unless your developers don't check in their tests (which would be weird) you would need all the test's dependencies if you want to run the whole tests suite anyway.
If the gems aren't necessary to run the app or its tests the gems don't need to be in the gemfile. Just have each developer create a gemset (I assume you're using RVM, if you don't you should) for the app and install whatever they need there, and then just add what the app needs to run to the gemfile.
You can use Bundler's without flag to exclude groups.
If you have the following Gemfile
group :jakubs_testing_tools do
gem "rspec"
gem "faker"
end
You can exclude them with bundle install
$ bundle install --without jakubs_testing_tools
http://gembundler.com/groups.html
It won't help you right now, but there's been an open feature request for Bundler to add support for a Gemfile.local for ages. It is planned for somewhere in the 1.x series, so stay tuned.
If your main problem is developer-specific IRB gems, there are a couple of workarounds in the issue's comments.
I suppose the install_if method (added recently) solves the problem:
install_if -> { `whoami`.strip == 'jakub' } do
gem "pry-rails"
end
See http://bundler.io/v1.14/man/gemfile.5.html#INSTALL_IF
Each developer can create their own branch - Bundler works fine with different branches having different Gemfile contents. It's a good idea for developers to prefix branch names with their initials, to avoid confusion or collisions.
(basically the same idea as in August Lilleaas's comment: gitignore)
Put the default/minimal Gemfile in SCM and then have developers change it on their systems and never commit. Have them add it to their inactive changeset in their SVN client (if they use one), other SCMs should have something similar.
This is how we do this in my company - works really well :)

Ruby gems in lib - spare tire principle

I'm working on a console ruby application (not rails!) I will be installing this application on several machines. I was wondering if there is a way i can build it so i dont have to install the gems i'm using for the app on each machine. I'd like to be able to just copy the directory to each machine and run it. Ideally, i'd like to put the gems in the lib folder or something and reference them from there, so i don't have to even install them on my dev machine. Is there a way to do this?
In .net, we call this the "spare tire" principle.
thanks,
Craig
How about using bundler?
Then you can include a Gemfile that specifies all the necssary gems and just run "bundle install" on each machine to pull them down.
If you really want to bundle them with the app run "bundle package" and the gems will be stored in vendor/cache.
You could take the same approach as rails allows and "vendor" your gems. This involves creating a new directory (rails uses vendor/gems) and unpack the gem into this directory, using gem unpack.
You then configure your load path to include all of the sub-folders below that.
Edit
You can configure your load path by doing something like this
Dir.glob(File.join("vendor", "gems", "*", "lib")).each do |lib|
$LOAD_PATH.unshift(File.expand_path(lib))
end

Resources