Why does my spring gem load in the wrong (or all) environment(s)?
I have this in my Gemfile and spring gem is not listed anywhere else in the file:
group :development do
gem 'listen', '~> 3.1.5'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
When I ran bundle exec rails console test (for the test environment), spring processes started and the Listen module was loaded in the rails console. I made sure all spring processes were stopped beforehand.
To do a sanity check, I removed the whole development group above and bundled. Spring and listen gems were no longer loaded, as I expected.
I faced this misunderstanding in production.
Here's how I solved it:
You can also fix this issue permanently by upspringing (removing the spring gem from) your bin/ executables:
bin/spring binstub --remove --all
Or
spring binstub --remove --all
You can now run the command below to get into rails console in production
rails c --environment=production
Also, to avoid this from occurring in subsequent occasions endeavour to make sure that the spring gem is only present in development and test groups in your Gemfile.
Moreso, when you're in production make sure you always provide the --without development test argument to the bundle install command
bundle install --without development test
and not the usual or common
bundle install
Please note: As an indication, whenever you run the command rails c or rails console and you see the output below:
Running via Spring preloader in process 26651
WARNING: Spring is running in production. To fix this make sure the spring gem is only present in development and test groups in your Gemfile and make sure you always use bundle install --without development test in production
It's an indication that the spring gem is running in your production environment, and it should be stopped or removed entirely from your bin executables.
That's all.
I hope this helps
Spring is generally used through binstubs - did you install the binstubs? If so this is the file your rails command is running through.
#!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
As you can see it will load spring anytime you use the rails command. There is no check for the environment. If you do not want to load spring you can use DISABLE_SPRING=1 rails c test.
According the spring gem github page, it looks like rails console will load up spring:
rails console, rails generate, rails runner
These execute the rails command you already know and love. If you run
a different sub command (e.g. rails server) then spring will
automatically pass it through to the underlying rails executable
(without the speed-up).
Also, this is worrying:
You must not install Spring on your production environment. To
prevent it from being installed, provide the --without development
test argument to the bundle install command
rails console (development) would make sense, but not rails console test (or another environment). It seems buggy to me, and a reason now why I don't like the gem.
Related
I do bundle install --without development test before my RoR application working in production because I want to remove gems only used in development or test, but the other day, this caused the problem.
I wrote some code and it works in development, but it contained module provided by the gem, which was installed as development gem's dependence. I used unintentionally so I cannot noticed by deployment failed. So I want to detect it. I'm using CI, so maybe I can notice if I do same bundle install as in production and something rails kicked, but if I do so, CI will take a long time so I don't really want to. I'd love to hear what you think.
edit: I think you haven't got my point yet, so let me explain it again.
for example, my Gemfile is like below;
ruby '2.5.7'
gem 'rails', '5.2.2.1'
gem 'pg', '>= 0.18', '< 2.0'
gem 'puma', '~> 3.11'
...
group :development, :test do
gem 'overcommit'
gem 'rails_best_practices'
gem 'rubocop' # <- this gem also install unicode_display_width(which has `Unicode::DisplayWidth`) as dependency
end
group :development do
gem 'brakeman'
gem 'debase'
gem 'rack-mini-profiler', require: false
gem 'ridgepole'
gem 'ruby-debug-ide', '0.6.0'
...
end
group :test do
gem 'simplecov'
...
end
and I used Unicode::DisplayWidth in my application because I totally thought it was the library ruby originally has(like csv). I don't want to do something like this again, but I may do carelessly, so I want to detect it.
It's not really clear what your problem is from your description. But have a look at bundle list to view installed gems https://bundler.io/man/bundle-list.1.html
Also, try bundle config and if you see any without's that you were not expecting, you can run bundle config --delete without to remove them.
I'm going to try and paraphrase what I think you're asking based on your updated question:
You want your CI pipeline to detect if you used a library in your code that wasn't made available via bundler*, but you don't want to slow your CI pipeline down with another bundle install command.
If that's the case, we have 3 separate pipelines/processes that we use:
CI/CD pipeline on Semaphore to run our automated tests. This pipeline won't catch the type of error described above
Separate pipeline using Heroku's review app feature which builds a "live" application using dummy/seed data, but production-like settings (e.g. bundle install --without development text). This may catch the type of error described above; you may have to use the review app to trigger the error and sometimes we don't
We also have a separate staging environment where user testing occurs, which is also production-like. This is where that type of error should definitely be identified (because we have users test features here by using the site)
This has been a common strategy at a number of projects I've worked on for catching this kind of error before it deploys to production.
* Because bundler in production is run bundle --without development test
I've got an API mode Rails 5 app that won't let me run rake routes or rails s. The error I get is:
$ rake routes
rake aborted!
LoadError: Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile
.../config/environment.rb:5:in `<top (required)>'
LoadError: cannot load such file -- listen
.../config/environment.rb:5:in `<top (required)>'
Tasks: TOP => routes => environment
(See full trace by running task with --trace)
I've verified that listen is in the development group in my Gemfile:
group :development do
gem 'listen', '~> 3.1.5'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
And that it's in my Gemfile.lock:
$ cat Gemfile.lock | grep 'listen'
listen (3.1.5)
spring-watcher-listen (2.0.0)
listen (>= 2.7, < 4.0)
listen (~> 3.1.5)
spring-watcher-listen (~> 2.0.0)
I've bundle updated, and bundle installed, and verified that gem install listen works. This was working earlier this week, but I'm not having luck going back through my commits.
$ ruby -v
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14]
I don't see it in vendor/cache but I'm not sure what to make of that...
$ bundle package | grep 'listen'
Appreciate the help!
Update:
I can "fix" the problem by putting gem 'listen', '~> 3.1.5' in the global Gemfile (and removing it from :development). Then all the errors go away and everything works, but that seems wrong.
If you are on rails 5 and you are using the default config/environments/development.rb file it will have this line of code in there.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
This requires the gem listen. This threw me for a bit as I was doing a rails 4 upgrades to a rails 5
edit:
Forgot to mention that if you comment that line of code out it will not need the listen gem anymore.
You might by mistake have set bundle install --without at some point, I sure did anyways.
To revert this run:
bundle config --delete without
I also ran bundle config --delete with as I manually set with option as well by mistake. Running both should get you back to default behaviour.
After having deleted the without config I could successfully run a bundle install again and afterwards my rails s, rails db:migrate etc. worked.
You can confirm if this is your issue by running bundle install and look at the second last line in the output. If it states:
Gems in the groups development and test were not installed.
It's for sure above solution should work for you.
I used this: bundle install --without development
Error:
Could not load the 'listen' gem. Add gem 'listen' to the development group of your Gemfile (LoadError)
After this, use that code:
bundle config --delete without
bundle config --delete with
Finally
bundle install
I'm posting this as an answer, but I don't like it.
I can "fix" the problem by putting gem 'listen', '~> 3.1.5' in the global Gemfile (and removing it from :development). Then all the errors go away and everything works, but that seems wrong.
I found an easy fix after a lot of trials of rebuild's
bundle config --delete without
bundle config --delete with
bundle install
If you accidentally built the gemset prior to seting your envirnoment correctly, then this may help clear out the problems.
I'm having the same problem by running rails c.
By reading this other Stack Overflow post I did realize that it is normal that both bundle exec rake command or rails console are running in a default production environment.
I figured I will solve the issue either by:
adding export RAILS_ENV=production in ~/.bash_profile
explicitly writing the environment in which I want the command to execute like bundle exec rake a_rake:task RAILS_ENV=production rails console --env=production etc...
I had similar problem today after upgrade from Rails 5.1.5 to 5.2.0. First time running the server there was the following 'missing assets' problem:
ActionView::Template::Error (The asset "asterisk_orange.png" is not present in the asset pipeline.)
Trying to precompile the assets shows the 'gem listen error':
$ bundle exec rake assets:precompile
rake aborted!
LoadError: Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile
My solution was to explicit set production environment:
$ RAILS_ENV=production bundle exec rake assets:precompile
This precompiles the assets w/o problems and the 'missing assets' problem was fixed.
I had the same issue. Thanks to #newdark answer I figured out the correct solution. Basically I wanted to deploy rails in production mode. But obviously forgot to set environment variable RAILS_ENV=production before running server.
So to recap, dependencies for production mode were installed while rails tried to start in development mode due to forgetting to set RAILS_ENV=production. If I went on to add gem listen to the production dependencies, I'd be running in development mode without being able to notice.
For me the solution was to do export RAILS_ENV=production before executing any rails commands and keep dependencies intact. Hope I managed to explain.
I had the same problem, i fix it by running
rails c -e production
I had same error when trying to generate mongoid database file.
but I created rails new project on ruby 2.5.1. Your ruby is 2.2. so the causality could be different in my situtation.
when I used rails new project, it was created in version 5.2, then I changed gem to 5.1.2 and problem arises. When I created with rails _5.1.6_ new in Gemfile there is generated additional pack for development.
group :development do
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
this way 'listen' showed me in gemfile automaticaly
I was working with Docker and encountered this error when executing
rails webpacker:install
It was happening because this line was being executed before
ENV RAILS_ENV production
RUN chmod +x bin/rails
ENTRYPOINT ["bin/rails"]
Fixed it by simply placing all rails commands after this
I'm trying to setup an application on a ubuntu VPS with rvm installed. The thin webserver works fine, but all the rake commands fails with same error message.
LoadError: cannot load such file -- cucumber/rake/task
I've this on my Rakefile:
require 'cucumber/rake/task'
I've tried with
gem install cucumber
gem install guard-cucumber
gem install cucumber-rails
gem install rake
bundle exec rake db:migrate
Nothing seems to work
#which ruby
/home/ubuntu/.rvm/rubies/ruby-2.0.0-p353/bin/ruby
#which rake
/home/ubuntu/.rvm/gems/ruby-2.0.0-p353#search-demo/bin/rake
What else could be or how I can debug this?
You can check the load path printing the $: var. check if you have the cucumber gem there and if it match the version that you have on your local machine, where I suppose is working.
If the gem path is not there, be sure it is installed with
gem list | grep cucu
Also compare versions with your local environment.
Check your Gemfile, make sure you dont have those gems on a group :development block or similar, cause you have probably set RAILS_ENV in your vps to production.
I just ran bundle update and capistrano got updated to 3.0.0 but now when I run cap deploy I get an error and can't figure out how to fix this. I have been updating my server every day without problem until this update.
cap aborted!
cannot load such file -- deploy
/home/mark/rails_apps/myapp/Capfile:1:in `load'
/home/mark/rails_apps/myapp/Capfile:1:in `<top (required)>'
capfile
load 'deploy'
load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks
I had to gem uninstall capistrano and selected version 3.0.0
(i.e. downgraded the gem to 2.x)
I had to run
gem uninstall capistrano
then update the gemfile with
gem 'capistrano', '~> 2.15'
and then run to reinstall the correct version again with
bundle update capistrano
Make sure you are using bundle exec (most likely you have multiple gem versions of capistrano)
i.e.
bundle exec cap -T
Instead of downgrading to Capistrano 2 use the new configuration from the current version.
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
See also this nice posting, which summarises the differences between Capistrano 2 and 3.
Add the related gems to your Gemfile
i.e. for
gem 'capistrano-bundler' # for capistrano/bundler
gem 'capistrano-rails' # for capistrano/rails/*
Do not downgrade to 2.x for this.
I had this problem today and pastullo's solution above fixed it except that I had to run gem uninstall capistrano (as markhorrocks answered) not bundle uninstall capistrano.
I also found this blog on bundler very useful: http://viget.com/extend/bundler-best-practices
Thanks for sharing this as it saved me heaps of time. x
The fastest way to fix this I have found is to backup the cap files (Capfile, config/deploy.rb, and config/deploy/*.rb) and then re capify (it's no longer called "capify"):
bundle exec cap install STAGES=staging,production
Then recreate your cap files from your backup. It will take you 5 minutes to do this and you'll be over the major Capistrano upgrade hump.
I used
bundle exec cap production deploy
instead of just cap production deploy
in my case I have changed my project ruby version. may be bundle also work here.
but I changed it to back what it was in previously.
ex:
rbenv local 2.4.1
In the rails project I'm working on I inserted support for rspec, cucumber and autotest with this Gemfile (partial)
gem 'rspec-rails'
gem 'cucumber-rails'
gem 'autotest-standalone'
gem 'autotest-rails-pure'
gem 'zentest-without-autotest'
however in order to run tests with autotest i need to execute bundle exec autotest otherwise it fails with this message
$ autotest
loading autotest/cucumber_rails_rspec_rspec2
Error loading Autotest style autotest/cucumber_rails_rspec_rspec2 (no such file to load -- autotest/cucumber_rails_rspec_rspec2). Aborting.
Now I'm developing on a Mac and I'd like to enable autotest-growl and autotest-fsevents gem, but if I insert those lines in my ~/.autotest
require 'autotest/growl'
require 'autotest/fsevent'
then I need to insert the corresponding gems in the Gemfile and everything works, but it breaks builds on my CI server (which is on Linux)
How to solve this without maintaining a different Gemfile for local and CI environments?
EDIT:
For the moment I solved with these lines in Gemfile
if RUBY_PLATFORM.downcase.include?("darwin") # I'm on Mac
gem 'autotest-fsevent'
gem 'autotest-growl'
end
It works both locally and on the CI server, I don't know if it mess something, for the moment it seems to work flawlessly.
Any cleaner way to do that is still welcome.
EDIT2:
I switched to groups solutions. While the previous monkeypatch works pretty well both in development and for continuous integration, it will gives you an error in production if you use capistrano bundler tasks for deployments or if you use bundle install --deployment option (which is advised in production)
When using the if RUBY_PLATFORM.downcase.include?("darwin") line you'll get this error on deploy.
# bundle install --deployment --without development test
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.
You have deleted from the Gemfile:
* autotest-fsevent
* autotest-growl
So my final solution to this problem is to include platform specific gems in a given group, say osx, and then in production and on CI server exclude it using bundle.
If you use capistrano to deploy put this in your config.rb
set :bundle_without, [:development, :test, :osx]
# capistrano bundler task
require "bundler/capistrano"
You might want to use groups in your gemfile, something like:
group :development do
gem "autotest-growl"
gem "autotest-fsevents"
end
and on the server you use: $ bundle install --without development
You can handle this by taking advantage of the different Gemfile environments (testing, development, production).
Your local box can be development while the CI server is your "production" environment.
With this in mind you can edit your Gemfile to use the appropriate gems depending on the environment.
Edit: Sorry, I think I scanned your post too quickly. But you can add your ~/.autotest to .gitignore so it wont be included on your CI server.