Run Rails App In Windows and Linux with different gemfiles - ruby-on-rails

I'm looking for a way to set up my rails app/Gem file to conditionally include a gem based on if I am in linux or not. I need the app in Linux, but it is not compatible with windows and I don't need it there anyway.
I was able to get everything working on Linux, but since I am using LESS stylesheets, I needed a javascript runtime. I didn't want to install Node.js, so i installed therubyracer, which is now in my gemfile. Then I pushed everything to github and cloned the app on my windows computer.
I tried to install all of the gems and realized there was no way install therubyracer on windows because of an incompatibility they haven't fixed yet (see therubyracer gem on windows)
I read elsewhere that I don't need therubyracer on windows because rails will automatically pick up the JScript runtime, so I'd like to have a simple way to only include therubyracer in linux. I read in does using ":platforms =>" in your gemfile work? that I can use an if block in my gemfile, but that it will cause my gemfile.lock to be regenerated every time. That was over a year ago though. Is there a way to only include therubyracer without regenerating gemfile.lock every time? Or maybe is gemfile.lock ok to remove my git and just have it generated every time locally?

I think you'll probably have to use that answer in the :platforms question and just ignore the fact that the gemfile.lock is regenerated. There's not much point in keeping the lockfile in your repository when it will be different on each platform. However, you can still maintain some of the control that the lockfile provides by manually specifying specific versions and dependencies in the gemfile.

Related

How do I force Bundler to get the right libv8-node for mini-racer?

I'm working on a Rails 5->6 update. When I run bundle update, we reach mini_racer, which requires libv8-node. When Bundler tries to get libv8-node v. 15.14.0.1, it tries to install <our local mirror path>/gems/gems-repos/gems/libv8-node-15.14.0.1-x86_64-linux-musl.gem, which is incorrect (this is a Debian VM) and the server responds with an error. gem install libv8-node works just fine.
The ruby-libv8-node page suggests there is a known issue with Bundler picking the wrong platform. Chasing down that rabbit hole it looks like there are proposed solutions but nothing released yet.
In the meantime, is there a workaround for forcing Bundler to use the right platform? This is Bundler 2.2.28 and Ruby 2.6.6.
Based on the README, it says
If a published binary does not work for you, bundler allows to force using the ruby platform via force_ruby_platform, which will compile from source.
so please try
BUNDLE_FORCE_RUBY_PLATFORM=1 bundle install
or BUNDLE_FORCE_RUBY_PLATFORM=1 bundle update rails
I've been dealing with this problem today. Whilst enabling the BUNDLE_FORCE_RUBY_PLATFORM=1 environment variable for bundler will work because it compiles from source, however this will be slow. Compiling libv8-node is no small chunk of code.
An alternative that worked for me was
BUNDLE_SPECIFIC_PLATFORM=1 bundle install
and that pulled the correct pre-compiled x86_64-linux binary for libv8-node. Much faster.
Note, I had already added x86_64-linux to the PLATFORMS section of the lockfile using bundle lock --add-platform x86_64-linux. This is the right thing to do anyway, but I'm not able to say for sure whether the BUNDLE_SPECIFIC_PLATFORM alone was sufficient to resolve or whether it was the combination.

Resolving gem version incompatibility

I am new to Ruby, Rails and gem management. One thing what I have noticed is that whenever I run bundle install (even within the project directory) it seems to install gems which affects other gem based Rails projects too.
For instance, assume that after running bundle install within one gem based Rail project (which installs a bunch of gems from the gemfile) I run into gem incompatibility issues. Now, these issues will manifest in all the other gem based projects too and will present themselves everytime I attempt to rackup
My questions are:
1) Is there a way to localize this damage (gem version incompatibility) to the current project and not have other projects affected?
2) Is there a good way to obtain a compatible set of gems or is the only way to look at the gem dependencies on a gem-by-gem basis (look at the tree) and figure out the compatible ones? I seem to be wasting a lot of time on this and if I fix one something else seems to break.
Please let me know what I'm missing here or point me to resources.
Thanks
It sounds like you're missing use of bundle exec
Description
This command executes the command, making all gems specified in the Gemfile(5) available to require in Ruby programs.
Essentially, if you would normally have run something like rspec spec/my_spec.rb, and you want to use the gems specified in the Gemfile(5) and installed via bundle install(1), you should run bundle exec rspec spec/my_spec.rb.
bundle install will install gems to $GEM_HOME which is shared by any apps using the same ruby and can result in multiple versions of the same gem being installed (this is expected and normal). If you don't then also use bundle exec to load only the gem versions specified in your Gemfile you can get incompatibility errors or unexpected behavior as ruby doesn't know which version of a particular gem to require.
RVM, rbenv, and other ruby version managers are useful tools for both isolating gems per project (which isn't really necessary when also using bundler) and for allowing multiple ruby versions to be installed on the same machine (which is not handled by bundler and can be very useful when developing multiple apps with different ruby version requirements).

Whether to specify Gem versions compulsorily in Gemfile or not for rails application

I want to know should I specify gem version for each gem I add to Gemfile or not. Earlier with few of my projects I didn't specified any versions for all the gems and bundler took care of it, which worked quite well as well.
But recently I got to work on few project which were under development for last 6 month. In that project, many of gem versions were specified in Gemfile only and Gemfile.lock was ignored. That caused a lot headache to finally resolve version conflicts and upgrade few gems.
Also got to know that it's bad practice to remove Gemfile.lock from application version control - nice article by yehuda - http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
So, my question is should I specify version for each and every gem I specifiy in Gemfile or just specify name and bundler will take care of version ? What is best practice to handle this ?
UPDATE -
Updating this question to correctly specify the problem, as a Gemfile sovles many problems :)
Prob 1 - Every developer should have same version of gems.
Actually adding Gemfile.lock into version control solved this problem. Developers just have to take care that they run 'bundle install'/'bundle' rather than 'bundle update' as this will update versions as well.
Prob 2 - Some gems version, if changed, brakes application code.
Actually with omniauth,there are this type of issues, as API are changed from one version to another. And yes, to keep application working, versions will need to be specified for this gems.
My Prob. -
So, in my gemfile, as versions for both A and B are strictly specified, and as they both depend on different versions of Z, which is there dependency, I even can't run the bundle install or bundle update. The only solution was to remove versions and let bundler to take the call. That's why I had question like -
Gemfile.version_specification_mandatory? #=> true/false
I think it's best to not specify gem versions in the Gemfile. On rare occasions, it may be necessary to specify a version--e.g., when a newer version breaks your app. But specifying versi­ons for all of your gems is usually overkill. The Gemfile.lo­ck file (which you don't edit, but you do check into version control) will keep newer releases of gems from being used in your app, until you explicitly upgrade to them.
If you are using the gem for something that is available only in a specific version, you need to specify the version.
Bundler installs the latest version or uses the available version on the system if no version is specified. This works for the developer because the latest version has the feature she needs. But if the feature gets lost in the future versions of the same gem and the version is not specified in the Gemfile, all subsequent installations of the gem for different people or different machines will produce undesired effects.
I have faced these problems particularly for will paginate 3's release candidate versions.
I don't recall how Bundler worked back in 2011, but in 2021, if you don't specify a version in your Gemfile, you can't assume that Bundler will always automatically install the latest version. Instead, Bundler will try to find the right combination of versions to make all your gems compatible with one another. This could lead to some gems being downgraded, which is probably not what you want or expect. Bundler will do this silently, without a warning message, which you could argue is a broken user experience.
On the other hand, when you specify a version, if there is a conflict, Bundler will let you know and you can then decide how you want to proceed.
I recorded a screencast recently to show a real example of an older version of a gem being installed when the Gemfile didn't specify a version number.

Can you disable Bundler in rails 3?

It causes so many deployment issues it's ridiculous. Most of the time I don't care what version of gems are used, just want to use the latest one.
UPDATE in response to comments:
Here are a couple of examples off the top of my head:
developer A is using a pre-release of a gem so when he runs 'bundle update', the Gemfile.lock is messed up for everyone else and if you deploy it, there goes your site.
A bug in a gem gets fixed so we run gem update across our servers, restart rails and yay, bug fixed! Oh, but wait, it's not fixed? Thanks bundler. What should have been an easy fix is now a full code deploy across our servers.
That's just a couple off the top of my head. At least let us decide if we want to lock in gem versions or perhaps at least allow a range of versions for instance any 2.X version.
UPDATE 2: And yet another issue when there are windows developers on the team
Here is what's showing up in a windows Gemfile.lock:
nokogiri (1.4.4)
nokogiri (1.4.4-x86-mingw32)
Wow, this is just awesome. Sure makes for easy teamwork and deployment.
I recommend starting to use two techniques with your development and deployment:
Specify version number of gems in your gemfile.
For example:
gem "rails", "3.0.1"
gem "will_paginate", "~> 3.0.pre2"
This way, when you decide you want to update rails, or will_paginate, change the version numbers in your gemfile.
Only update certain gems
Rather than the generic bundler update command, run
bundler update rails
This will only update the rails gem to the newest version, rather than get the latest of all gems.
If you use both 1 & 2, you'll have a happier experience.
Then, simply, don't check your Gemfile.lock into source control. All of the specific problems you listed are solved.
Of course, you are sacrificing the enormous advantage that Bundler gives you over any other dependencies management system.

Managing gem versions/dependencies for Rails

Just a bit of background, I come from a strong C#/staticly typed background. Therefore I tend to think in terms of .dlls. So if I was working in a project, I'd reference my required dlls and that would be that.
Being new to Ruby and Rails I find I might be doing something wrong. For example, I create a Rails app at home using the gems I have locally. Using a different computer (say a work computer) I attempt to work on the project only to find I'm using different versions of the gems. After carrying out a bundle install I'm back to a working project.
The issue I have with this is that my gem library becomes 'messy'. I end up with several versions of the same gem. Is this the way others work? When using a gem (from a require) will it default to the latest version? I feel as if I'm not managing the dependencies correctly, though as I've mentioned I'm new to the world of Ruby.
Should I just include my dependencies, then perform a bundle install each time I have different/missing dependencies? What happens if I wish to upgrade to a newer version of a gem? Would it be a case of updating the gemfile that bundle uses and getting on with it?
Yes, bundler is the way to go to work with dependancies with Ruby on Rails. Why ? First, because it's shipped with it (at least for version 3.0). Second, because it's simple as hell (unlike maven with Java).
A non exhaustive list of feature :
it lets you declare one or many gem repository to fetch gems from
to group your dependencies by environment (development, production...)
to specify version you'd like
and so on. For more on this, check this http://gembundler.com/rationale.html
Regarding your question : yes, bundler will take the latest version available is none is specified.
Also, I would add a disavantage : you cannot specify a gem version depending on the OS. For example, nokogiri has a linux version AND a win version.
The default behaviour when requiring a module in a gem is to assume you want the latest version of the gem if you have more than one installed. You can change this by specifying which version you want in a specific application like this:
gem "rails", "2.3.8"
Before you require anything from the gem. This ensures that this application will use the specified version of the gem, even if a newer one is installed.
You can of course clean out obsolete versions of your installed gems whenever you don't need them again, or if you use bundler consistently: just wipe everything and run bundler again to get just your required gems installed.
Another useful tool is the Ruby Version Manager (RVM), in addition to handling different versions of ruby it provides a feature called gemsets which allows you to isolate different applications or environments from eachother. That is App A can have its separate gemset with all its required gems, and App B have another gemset with only its required gems. This will reduce the clutter in your dependencies quite a bit.

Resources