Ruby: Rails: Which version of a gem is used? - ruby

I have a Rails 3 application which has the following line in the Gemfile.
gem 'sqlite3', '1.3.6'
However, if I list my local gems I get:
> gem list sqlite3 --local
*** LOCAL GEMS ***
sqlite3 (1.3.6, 1.3.4)
When my Rails apps does a
require 'sqlite3'
which version of the gem is selected? Is it that the first gem in the list is selected? Is there a way to tell the Ruby runtime to use version 1.3.4 even if version 1.3.6 is installed, and mandated by the Gemfile?

You could find out with
bundle exec gem list sqlite3

Either the Gemfile will specify a version or Gemfile.lock will have the version.
Examples:
Gemfile:
gem 'tiny_tds', '0.5.0'
Gemfile.lock:
tiny_tds (0.5.0)
Edit: if you want to see the version, use iltempos' suggestion or in the rails console type
1.9.3p194 :001 > SQLite3::VERSION
=> "1.3.6"

the Gemfile list all the dependencies of your Rails application, you can add constrains about the version to use for each gem. In your example you specified that your application depends on sqlite3 1.3.6 so it will use the version 1.3.6.
In general the exact version of the gems required by your application are in the Gemfile.lock.
There are several syntaxes you can you to specify the versions:
gem 'gemname', '1.2.3' - Requires gemname version 1.2.3
gem 'gemname', '>= 1.2.3' - Requires gemname version 1.2.3 or any higher version. Can break things
gem 'gemname', '~> 1.2' - Require gemname 1.2 or a minor update like 1.2.9. You get updates but not mayor one which could break compatibility
The interesting thing to note is that once the Gemfile.lock is written and checked in your version control, it's shared between all the members of the team that all will use the same, exact, versions of the required gems.
If you need to update a required gem you can do that in 2 steps:
Update the Gemfile if needed
Run bundle update gemname
The step 2 will download the new gem version (if there is a new version respecting the constrain in the Gemfile), install it and update the Gemfile.lock accordingly.

Related

How can `gem list` show multiple `default` versions for a gem?

When I run gem list bundler, I get the following result
+ gem list bundler
*** LOCAL GEMS ***
bundler (default: 2.3.22, default: 2.1.4)
How is it possible that two versions are marked as default? Is there a way to update the default one?
Context
The reason I ended up looking into which is the default Bundler version is that I've been running into this warning on a self-managed CI machine on and off for a while:
Gem::LoadError: You have already activated bundler 2.3.22 [or whichever latest version is available], but your Gemfile requires bundler 2.1.4.
I looked into my Gemfile.lock and it requires bundler like this:
bundler (>= 1.12.0, < 3.0.0)
So I'm guessing at some point, Bundler activated (which I believe means selected for runtime use) version 2.1.4 because that was the default available one.
I hope to be able to forever prevent that error by forcing the latest version of bundler to be the one used at runtime, but I'm not sure how to achieve it.
That is, how can I get the gem list bundler output to not show default: 2.1.4?
Thanks for your help!
To delete the duplicate default versions
gem environment
you will find the installation directory:
INSTALLATION DIRECTORY: /home/seb/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0
in /specifications/default you will find your .gemspec files, you will remove your duplicate one
rm bundler-2.2.31.gemspec
to verify: gem list bundler
(2.2.31, 2.2.29, default: 2.2.15)
you can update the default version with gem install bundler:2.3.18 --default but it appears that bundler use a arbitrary version that fit his needs. If you want use a specific version to bundle the Gemfile, you add it in your gemfile
gem "bundler", "~> 2.3"
it will appear at the end of the gemfile.lock
BUNDLED WITH 2.3.18

Bundler could not find compatible versions for gem "globalize":

Hi everyone I have recently started developing with this framework, I am having difficulties in starting a project locally.
When I go to run a
bundle install
I get this error message:
Bundler could not find compatible versions for gem "globalize": In Gemfile:
globalize java
globalize-accessors java was resolved to 0.2.1, which depends on
globalize (>= 5.0.0, ~> 5.0)
Could not find gem 'globalize (>= 5.0.0, ~> 5.0)', which is required by gem 'globalize-accessors', in any of the relevant sources: https://github.com/globalize/globalize.git (at master#bcfa30f)
Bundler could not find compatible versions for gem "globalize-accessors": In snapshot (Gemfile.lock):
globalize-accessors (= 0.2.1)
In Gemfile:
globalize-accessors java
Running `bundle update` will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict.
this is the part of the gemfile concerned:
########## Globalization
gem "route_translator", git: "https://github.com/enriclluelles/route_translator.git"
gem 'activemodel-serializers-xml'
gem 'globalize-accessors'
gem 'globalize', github: 'globalize/globalize'
gem 'kaminari', github: "amatsuda/kaminari", branch: '0-17-stable'
gem "kaminari-i18n"
i also tried to run bundle update but it didn't fix the problem
Ruby version:2.3.3
gem -v:2.5.2
The version of globalize in your gemfile seems not to correspond to the version required for globalize-accessors.
Try installing globalize like so :
gem 'globalize', "~> 5.0"

ruby gem hashdiff - how to upgrade to 1.0 to stop deprecation warnings

The gem hashdiff has problems with another gem using the same namespace, it gives the deprecation warning:
The HashDiff constant used by this gem conflicts with another gem of a similar name. As of version 1.0 the HashDiff constant will be completely removed and replaced by Hashdiff. For more information see https://github.com/liufengyun/hashdiff/issues/45.
(The link is to a long conversation, even reading it I am not sure how to upgrade this particular gem)
My /Gemfile does not have hashdiff in, however there is a gem which depends on it, in /Gemfile.lock there is hashdiff (0.4.0).
To force hashdiff to upgrade to 1.0, I added gem 'hashdiff', '~> 1.0' to /Gemfile and ran bundle update hashdiff but:
Fetching gem metadata from https://rubygems.org/.
Could not find gem 'hashdiff (~> 1.0)' in any of the gem sources listed in your Gemfile.
Alas rubygems does not have version 1.0.
How are we people dealing with the deprecation warning? Ignoring it until the gem becomes available? Or something else?
Bundler doesn't consider beta versions of a gem when solving dependencies unless you explicitly tell bundler to use such a beta version.
I would just add that gem together with a comment to my Gemfile
# FIXME: Force bundler to use the beta version of the hashdiff gem
# `hashdiff` is a dependency of the `webmock` gem. Feel free to remove
# the following line from this Gemfile as soon as hashdiff 1.0.0 is
# officially released.
gem 'hashdiff', '>= 1.0.0.beta1'
gem 'webmock'
and then run bundle update hashdiff.
Update
Version 1.0.0 of the hashdiff gem was released on 2019-07-15. Therefore this workaround is not needed anymore and a bundle update hashdiff – without the need to update the Gemfile first – should solve the issue.

How to Specify Gem Dependency Version at Gem Install Time

I am working with a gem that has a dependency whose version must vary depending on which Ruby version is running when the gem is installed. Specifically, the current version of the nio4r gem requires Ruby version >= 2.2.2, and the async gem that needs nio4r should ideally be able to run on any Ruby version >= 2.0.
I tried putting some code into the gemspec file to vary the version, but it seems that it is executed when the gem is built, not when it is installed. In other words, the nio4r version is hardcoded into the gem based on whatever version of Ruby is used to build the gem. Here's the code I tried in the gemspec (say is an OS X command to speak a string and was very helpful in knowing what was happening and when; I would of course remove it later).
# Recent versions of nio4r require a Ruby version >= 2.2.2.
# If the version used is earlier, load an earlier version of nio4r.
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.2.2')
`say Installing latest version of nio4r`
spec.add_runtime_dependency "nio4r"
else
`say Installing nio4r version 1.2.1`
spec.add_runtime_dependency "nio4r", '1.2.1'
end
As I said, this was executed on gem build and not install. I am aware that I can use bundler for this kind of thing and put the specification in the Gemfile, but as far as I can tell that file will not be used when the gem is gem install'ed.
How can I get the dependent's gem version to vary at gem install time?
I'm looking for a solution that is automated, that is, does not involve any intervention by the user of this gem. Also, this gem will be installed as a result of installing another gem, so I don't want the user to have to keep up with changes to its dependent gem and have to modify the Gemfile manually. It would kind of be a violation of the Law of Demeter.
There is not a way that I know of to dynamically update the ruby version in the gem's gemspec file, however you can lock it to a specific ruby version:
spec.required_ruby_version = '>= 2.2.2'
Alternatively you could suggest to consumers of your gem (in the README perhaps) that they must force a specific version of nio4r if they are using versions of ruby older that 2.2.2.
In Gemfile for a new Ruby:
ruby "2.4.1"
gem "keiths_gem"
In a Gemfile with an old version of Ruby:
ruby "2.1.0"
gem "keiths_gem"
gem "nio4r", '1.2.1'

How to specify minimum bundler version for Gemfile?

When my Gemfile is using :mri_20, and previous versions of bundler do not support that, is it a good idea to add
gem 'bundler', '~>1.3.5'
to the Gemfile? Is there a better way to enforce a minimum bundler version?
This won't have any affect on the bundler used to manage the gems in the Gemfile. The version of bundler that's used is the one that's available in your current ruby environment.
The best way to manage this is with gemsets - you can create a gemset with a known, working version of bundler and always switch to that gemset when working with that project.
To check the bundler version, run:
$ bundle --version
Bundler version 1.3.5
If you want to enforce the bundler version when running bundle install, put this at the top of the Gemfile:
# Gemfile
if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.3.5')
abort "Bundler version >= 1.3.5 is required"
end

Resources