bundle update rails resolving to 6.0.1 release candidate - ruby-on-rails

I'm trying to update rails from 5.2 to 6.0. In my Gemfile I have declared:
rails (~> 6.0) was resolved to 6.0.1.rc1
My expectation there is that I'd end up with 6.0.4 the ~> meaning optimistically resolve to the latest 6.0.* version?) Resolving to a release candidate isn't something I want to do.
I can specify it directly, of course, but I'd rather not tie the Gemfile to a specific version and count on bundler to resolve it correctly.

One quick fix would be to alter your Gemfile. If you want to retain the optimistic ~> 6.0 operator, you can add a second matcher for the version, like this (and thus report an error if it can't do so):
gem 'rails', '~> 6.0', '>= 6.0.4'
I often use this pattern to lock in security patches without losing the flexibility of the ~> operator.
I'd guess that something is preventing bundler from using a later Rails gem version - that is, you have a dependency that's locking your gem version to 6.0.1. If the above doesn't resolve it, can you post the relevant portions of your Gemfile in your question? And search Gemfile.lock for rails to see whether you have any gems that require rails 6.0.1 and not later versions.

Related

What can be done about an unsafe/outdated gem dependency of a required gem?

I have bundler-audit (a check for known vulnerable gems) included as a pre-commit and in CI. It comes up with a known vulnerability in a previous version of the nokogiri gem and recommends I upgrade.
But here's the rub: the vulnerable gem is among the transitive dependencies of Rails and a few other gems I can't strip out. Some of them use a pessimistic version specifier which explicitly precludes the version of nokogiri to which I'd need to upgrade.
What does one do in a situation like this? Any advice?
If the current Rails 4.x gem has this dependency, file a bug against Rails.
I'd be very surprised if the current 4.x version of Rails has a dependency on an insecure version of a gem, though.

specify gem version to be used with a specific gem?

This is more of a general question, I'm new to rails.
I trying to use a gem that requires an older version of json, json -v 1.6.5
other gems in my rails application depends on newer version of json, json -v 1.8
I'm wondering if it is possible to specify json version to be used with a specific gem?
Thank you
No it's impossible to use 2 versions of a gem at the same time.
Use 2 versions of gem at same time
If bundle update doesn't resolve the dependencies I would fork on of the gems you need to use the same version as the other and then point to my fork.
gem 'some_gem', git: 'https://github.com/user/My-Fork.git'
Each of your dependencies will have a version constraint and your project can only use one version of each gem.
The answer to your specific question is that yes, you can control the version of an indirect dependency by specifying which version to use directly in your gemfile. However, this version must satisfy the version constraint of the direct dependency.
A brief example. Let's say your gemfile looks like this:
source 'https://rubygems.org/'
gem 'somegem', '~> 1.0'
And your gemfile lock looks something like this (note, some parts omitted for brevity):
GEM
remote: https://rubygems.org/
specs:
somegem (1.0)
json (~> 1.8)
json (1.8)
The Gemfile.lock indicates that somegem is dependent on json and that the json version must be greater than or equal to 1.8 but less than 2.0 (read more about the ~> operator here).
If you want to use lets say json version 1.9, you can modify your gemfile or use bundler commands to update the version used in the lock file.
E.g.
source 'https://rubygems.org/'
gem 'somegem', '~> 1.0'
gem 'json' , '~> 1.9'
In your specific case, if you have two dependencies that use conflicting versions of an indirect dependency, the gems will be incompatible. However, this example is meant to show that you can specify the version of an indirect dependency IF it meets the constraint specified by the direct dependency.
Rails uses Bundler to manage Ruby dependencies. An overview of the gemfile would be a good place to start learning how to manage your project's dependencies.

Why prawnto gem installs rails 3.x when there is already a rails 2.x?

I have rails (2.3.5) and prawn (0.12.0) installed. When I install prawnto, gem installs rails version 3.2.6 also.
The dependency of prawnto is:
prawn >= 0
rails >= 2.1
Why gem install Rails 3.x when the prawnto dependency is already there?
tl;dr Use Bundler. It rocks.
Alright, this is basically down to how dependency resolution works in RubyGems. If you're not terribly familiar with it, get up to speed real quick like with the Primer panel from this XKCD comic. RubyGems dependency management and the Primer storyline are very similar in terms of complexity.
When a gem specifies a dependency of, say rails >= 2.1, when you go to install that gem, RubyGems conveniently ignores all the gems that you've currently got installed and then queries the web API to find the absolute latest version of Rails that's greater than or equal to 2.1.
It will find, as of this writing, version 3.2.6, and so will dutifully install that version of Rails because it fits the dependency requirements. It will also install every single dependency of Rails, and their dependencies, and the sub-sub-sub-sub-dependencies all the way down until there's not a gem left without a dependency installed.
I won't go into exactly how that works because it makes my vision go blurry when I think about it.
Now, if you were using something that's not pure-RubyGems such as Bundler, you'd be able to have a Gemfile like this:
source 'http://rubygems.org'
gem 'rails', '2.3.4'
gem 'prawnto', '0.1.1'
And then run bundle install and then something magical will happen. Bundler will figure out the dependencies for all the gems specified in the Gemfile, as well as the gems that they depend on, and then install only those gems.
This means that if you have prawnto wanting Rails >= 2.1, it won't install 3.2.6 because there's another dependency saying that Rails must precisely be 2.3.4. So therefore Rails 2.3.4 will be installed.
If you have conflicting versions, with a gem A specifying a dependency on gem B of ~> 1.0, but then gem C specifying a dependency that gem B must be '= 0.5.0', Bundler won't be very happy and will raise an error because the dependencies can't be resolved.
I'd really recommend using Bundler for all your Rails projects. Even those that are running on Rails 2. There's a page on the Bundler website which will get you started with a Rails 2.3 project and Bundler.

Beginning with Ruby on Rails. How do Gemfile and how gems work when specifying versions to download?

I tried reading the documentation but this still wasn't clear to me:
Suppose my I have the following statements in my Gemfile:
source 'https://rubygems.org'
gem 'rails', '3.2.2'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3'
gem 'json'
...
I'm trying to learn how to use Ruby on Rails this website: http://ruby.railstutorial.org/ and it says that I need to have the sqlite3 gem for this version of rails (3.2.2).
My question is: if I don't specify the exact version of the sqlite3 gem for the system to download when I run bundle install then will it install the latest version that works with the version of rails and ruby that I'm working with (suppose it's 3.2.2 and 1.8.7 p-352 respectively) or will it just download the latest version of the sqlite3 gem available whether it works with what I have installed or not?
I'm not really sure how this aspect of the Gemfile works and the documentation hasn't been clear or I haven't found where it explicitly says this or otherwise.
So, it will install the latest version of sqlite3 that is compatible with the dependencies specified by the other gems you've listed.
Say, rails said it only worked with sqlite3 that was greater than 1.0 but less than 4.0, it might install 3.9.5. I'm making all these numbers up, just an example.
In fact, I don't know if rails does specify any particular versions of sqlite3 it requires. Presumably 'json' doesn't either, since it's got nothing to do with databases. If none of the other gems you list specify any requirements for sqlite3, it'll just install the latest version available.
'bundle install' is using bundler, some more about how it resolves dependencies is here.
So bundler will download the latest gem that meets the requirements of all the other gems you list. Say you listed a gem A which required sqlite3 earlier than 2.0 and a gem B that required sqlite3 later than 2.1 -- 'bundle install' would complain and say it can't satisfy them all.
This relies on the gems own advertisements of each of their own requirements for the other gems they rely on though. Sometimes they can be wrong, or missing. It may be that rails doesn't actually specify what version of sqlite3 it requires -- since it doesn't actually require sqlite3 at all (you don't have to use sqlite with rails), this may very well be. In which case bundler can't do much but get the latest version of sqlite3. Which doesn't guarantee that version will work. But it can only do so much.
You also mention the issue of compatibility with specific versions of ruby, like 1.8.7-p352. Bundler is less capable there, you can't generally count on it knowing what version is compatible with a particular version of ruby (because there's not a great way for gems to express this in a way that bundler can use, alas).
But in general, things work out. If you don't know or care what version of sqlite3 (or any other gem) you want, but know you want one -- do what you did, run 'bundle install', see if it works. It probably will. If it doesn't, google the error message and you'll probably find someone explaining why it didn't and what you need to do instead.
PS: If that wasn't enough. sqlite3 is sort of an odd case, because while Rails is designed to work with it, it's not required. But Rails by default, when creating a new app with latest version of rails rails new my_app, will already put sqlite3 in your Gemfile for you. And it'll do it just like you did, without a version constraint. That's reason to feel pretty confident it will work fine. Note that in rails 3.2.2, rails new my_app will put some other things in your Gemfile that do have more specific versions listed, like gem 'sass-rails', '~> 3.2.3', because while those things aren't absolutely required for Rails (or else they'd be expressed as requirements and not need to be explicitly in your app's Gemfile), the rails installer knows that only certain versions will work.
Fairly new to Rails as well so correct me if I am wrong.
The Gemfile looks to the gems directory for the gems listed and has no impact on actually "installing" them. Performing a "gem install" command without a version will grab the most recent version listed no matter what your Gemfile says. When you "bundle install", that is when version-specific lookups happen in your gems directory.
Bundler always looks at your Gemfile.lock file first when you're doing bundle install. If you open that file, you'll see the gems as well as the version used by your application. This is convenient for existing projects because you're always sure that every other developer involved with the project will be working with the same gem versions.
If it doesn't find that file (i.e. doing rails new projectname), or the specified gem or version in Gemfile isn't consistent with Gemfile.lock, it will download the latest or specified version of the gem.

gem list is showing two versions of a Ruby gem immediately after updating the gem

I just updated the mime-types gem with gem update mime-types. gem list displayed mime-types (1.16) prior to updating. After the update gem list shows mime-types (1.17.2, 1.16). Why are two version displayed?
More info: I have other Rails projects on the same computer. I have not updated the mime-types gem in any other projects. Running gem list from another project's directory (where mime-types has not been updated) displays mime-types (1.16).
You have both versions installed. If you want to delete old versions (which will not always will be possible due to dependencies) use gem cleanup.
Which version of RubyGems do you have? gem -v
This is interesting: I have the newest version of RubyGems but my system behaves differently:
gem list => all the gems, all the versions. No matter from where I call it.
gem list --local => same as before but user-wide.
bundle list => all the gems in a project (one version per gem)
The same goes for bundle update and gem update.
bundle update replaces the old version by the new one (the dependencies are taken care by bundler), but gem update keeps both. So if you want to keep only the newest version, run gem cleanup.
bundle outdated might be useful: it displays the outdated gems in your project (based on rubygems.org)
This can happen because of gem dependencies.
For example if another gem depends on that gem, and the other gem does not have a version specified for it, and(/or) it gets updated and if its dependency on that gem's version changes... well you get the idea.
Sometimes I do a bundle and I see a ton of new versions getting downloaded. All due to changed... dependencies.

Resources