Running bundle from rails shell command - ruby-on-rails

I have a Rails 4 application that executes several shell commands and everything works fine, but now I am trying to execute a shell command from it that checks the bundle of a different app or even an engine not used by this app, and all I get is the result as if it was checking its own bundle.
This is probably confusing so let me try to make it clearer:
Rails app
|--operations folder
|--app1
|--engine1
|--app2
now the rails app executes a shell command to check the bundle of any of those apps/engines in the operations folder like this:
out = %x[cd operations/app1 && bundle list 2>&1]
but the result is the list of gems used by the executing Rails app, not the list of gems from app1 that i want to check.
Why is that happening? I've also tried specifying the Gemfile using the --gemfile= option to no avail. how can I execute bundle operations on the target app?
The reason for this is that I have built a continuous integration application that tests and builds packages from our other apps and engines and sometimes some of the apps/engines require gems that the CI doesn't have, so running their tests fails and I wanted to make the CI install them before running the tests if it doesn't have them.

By default, child processes inherit the environment set up by Bundler.
To suppress this behaviour, call Bundler.with_clean_env with a block that contains the commands you want to run in the clean environment:
out = Bundler.with_clean_env { %x[cd operations/app1 && bundle list 2>&1] }
For more on this, see http://bundler.io/man/bundle-exec.1.html#Shelling-out

Related

How to check from the command line if a gem is in the bundle

My question is like Programmatically check if gem in bundle? , except that I'm wanting to check from the command line, not from within the program.
I've set up CI with codeship for a Rails project, and one of my tests involves running haml-lint. Today, I got a failure because an old branch of the project that doesn't have haml-lint installed was pushed to the repository. I want to be able to test whether haml-lint is installed, so that I won't try running it if it isn't installed.
I could do
bundle exec haml-lint --version
or possibly bundle list plus some text handling, but I want to know if there's something more concise and intention-revealing.
Running
bundle list | grep haml-lint
will work for you. But implementing program code for that is a clear abuse of Rails-way. For avoiding things like that you just better keep Gemfile.lock in your repository and make it fail in case you removed needed gems for some unknown reason. Because how things are handled in Rails and it's why we need CI, to avoid things like that before hitting production. Building additional code to avoid that kill off all bonuses of that.
You can do gem('haml-lint') in from the console, or you can grep for a string in the command line with grep 'haml-lint' Gemfile.

Run a command in the context of a different app

I have two rails apps on the same server, let's call them A and B.
I am trying to have app A restart app B via app B's own capistrano task. Unfortunately, even after cd-ing to app B's directory, it is trying to run app A's capistrano instead. Am I missing something?
example code
system("cd /apps/appB/current && pwd && bundle exec cap:restart")
pwd correctly returns the path of appB (/apps/appB/current), however, in there is a traceback for cap:restart. This is because it is still trying to run the cap command in the context of appA, e.g.
/apps/appA/shared/bundle/ruby/1.9.1/gems/capistrano-2.15.4/lib/capistrano/configuration/loading.rb:152:in 'require': cannot load such file -- airbrake/capistrano (LoadError)
from /apps/appA/shared/bundle/ruby/1.9.1/gems/capistrano-2.15.4/lib/capistrano/configuration/loading.rb:152:in 'require'.
I tried without 'bundle exec', and have tried some other ways of making system calls. I also created a bash script in another directory and tried to run it that way.
All methods described exhibit the same behaviour.
Your help would be greatly appreciated =)
You need to use Bundler.with_clean_env to ensure that your subprocess doesn't pick up your current Bundler environment:
Bundler.with_clean_env do
system("cd /apps/appB/current && pwd && bundle exec cap:restart")
end
This is essentially the same problem as Install bundle of gem within other rails application
Since you said your apps are using Unicorn, you can signal from app A to app B (or the other way around).
Read this page: http://unicorn.bogomips.org/SIGNALS.html
The only thing each application needs to know is the pidfile path of the other application. So look at your Unicorn config and see where it's storing that.
You could either read the PID out of that pidfile and kill it from Ruby:
pid = File.read(path_to_other_application_pidfile).chop
Process.kill("USR2", pid)
Or you could use backticks to execute shell commands
`kill -s USR2 \`cat #{path_to_other_application_pidfile}\``

Run Rails commands outside of console

With my large application, the Rails console takes a while to load up. Is there a way to single commands more easily?
I'd also like to be able to automate stuff, and echo "query" | rails console isn't a great way to do things.
Thoughts?
EDIT: What about a long-running process that I can ping queries to whenever I have need?
There are two main ways to run commands outside console:
Rake task which depends on :environment
rails runner (previously script/runner), eg:
$ rails runner "query"
Both are pretty well documented on the rails guide: https://guides.rubyonrails.org/command_line.html#bin-rails-runner
Both of these methods will still take the same time as a console to fire up, but they are useful for non-interactive tasks.
Just pipe it in:
echo 'puts Article.count' | bundle exec rails c
It should now be a lot faster than when then the question was originally asked, because of Spring. It's not immediate, but still a lot faster than spinning up the whole app. Use this for the fast lane, it should run in under a second (assuming your required command is fast):
echo 'puts Article.count' | spring rails c
If you really want a single long-running process, you could easily do it by creating a controller action that simply runs whatever you POST to it, then send commands to it using curl behind an alias. The action would of course be completely insecure and should be triple-guarded against running anywhere near production, but it would be easy to setup.
Solution: bundle exec command allows us to run an executable script in the specific context of the project's bundle - making all gems specified in the Gemfile available to require in Ruby application. In addition it eventually avoids any conflicts with other versions of rake installed globally.
echo '<command>' | bundle exec rails c
for more information look at the documentation of bundler
example:
configuration_item=$(echo 'ConfigurationManager.getKey("authentication_method")' | bundle exec rails c )
echo $configuration_item
#output:
MFA_authentication

Clearing the test database between unit and functional tests in Rails (factory_girl)

Recently I switched from fixtures to factory_girl to test my Ruby on Rails application. If I run rake test:units, to run the tests in my /units directory, they all run perfectly. The same is true if I run my functional tests (in my /functional directory) with rake test:functionals.
However, if I simply run rake test, to run both my unit and functional tests together, my validation fails on the second group of tests (functional, in this case), with the message "Validation failed: Name has already been taken."
I believe this is caused by the functional tests creating objects with the same parameters as the objects that were created in the unit tests -- leading me to believe that the test database isn't cleared in between the unit and functional tests.
I use factory_girl's sequencing to have unique attributes for objects, which means that factory_girl is being reset between tests, while the database is not. What can I do to solve this problem? Is there a way to clear the database between my two test packages?
A command line solution to clear (reconstruct) test database:
rake db:test:prepare
Try writing this in your test/test_helper.rb
eval IO.read(File.expand_path(File.dirname(__FILE__) + "/../Rakefile"))
class Test::Unit::TestCase
....
#db:test:prepare won't work, don't know why,
#as DROP DATABASE won't execute (me on PostgreSQL).
#even if I write,
#ActiveRecord::Base.connection.disconnect!
Rake::Task["db:reset"].invoke
end
It's not a recommended solution. It makes tests slower, but it works.
A rails plugin called "override_rake_task" could be used to override Rake task "test" which is defined inside if Rails gem. This is a very simple task that executes 3 other tasks one after another: test:units, test:functionals and test:integration. You could include the execution of "db:test:purge" task to clear the test DB before executing test:functionals.
Apparently if you are not using this plugin and if you define a task in your rails application with the same name, rake would execute both tasks: the default and yours.
The above solutions didn't work for me. If you are trying to reach out to an external database running unit tests can give some weird errors. For some reason they do not get cleared after running the test so you have to run rake db:test:purge after running the unit tests. Put this in your Rakefile and it should fix it.
Rake::Task["db:test:prepare"].enhance do
Rake::Task["db:test:purge"].invoke
end
I ran into this problem on my machine. I was getting test failures, from validation problems because the database wasn't properly being reset between tests. Some back story about my situation:
-I had a linux box, and was running code, that I knew should pass the tests.
-I bought a Mac with Lion installed and attempted to get my code running on that machine.
-I installed mysql from source
Everything installed fine. My database worked, and rails could access it. When I ran tests however, I ran into the same problem. I came across this post, and tried both the proposed solutions (even though it didn't seem like a code issue, it seemed like a configuration problem since rake ran fine on my linux box). None of the solutions works.
I removed mysql:
sudo rm /usr/local/mysql
sudo rm -rf /usr/local/mysql*
sudo rm -rf /Library/StartupItems/MySQLCOM
sudo rm -rf /Library/PreferencePanes/My*
sudo rm -rf /Library/Receipts/mysql*
sudo rm -rf /Library/Receipts/MySQL*
sudo rm /etc/my.cnf
sudo rm /usr/local/bin/mysql*
I reinstalled mysql with homebrew instead of manually doing it from source (this step was courtesy of a co-worker's advice):
export PATH="/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH"
brew install https://github.com/adamv/homebrew-alt/raw/master/versions/mysql51.rb
unset TMPDIR
mysql_install_db
I then re-ran rake, and all the tests passed. If anyone is on Lion, built mysql from source, and ran into this problem, this might be a solution.
DB cleaner is a pretty nice gem specifically for cleaning between tests. It gives a few options including wrapping every test in a transaction and rolling back, truncating the table, and deleting.
It also supports multiple ORMS in case you're not using/ using more than active record.
The documentation is pretty good and includes examples of using it with MiniTest, Rspec, and Cucumber.
https://github.com/bmabey/database_cleaner

Netbeans and Rails: Is there a way to make the Run option in netbeans also start thinking_sphinx?

I don't want to keep sphinx running all the time on my dev machine. I'd like a way to automatically execute rake thinking_sphinx:start when I run my app via netbeans. Is there a way to do this
[also - I am using Windows]
Thinking sphinx needs to run as a separate process.
You will need a third-party program called PsExec to do this. Otherwise you won't be able to start a background process using Ruby on Windows.
First of all download PsExec here. Unpack (at least) psexec.exe and run it once manually - you have to agree to the license :-/.
After that add the following line to script/server of your Rails app:
system 'PATH_TO_PSEXEC/psexec -d rake.bat'
Now you create the rake.bat with the commands to run in parallel to your server. Put the file with the following contents into your Rails app's root directory.
rake thinking_sphinx:start
This line should do the trick, but it may fail e.g. when NetBeans' JRuby version differs from Ruby installed on your host. Or if Ruby isn't installed at all. In that case you should call rake with the complete path of JRuby:
"PATH_TO_NETBEANS/ruby2/jruby-1.2.0/bin/jruby" "PATH_TO_NETBEANS/ruby2/jruby-1.2.0/bin/rake" thinking_sphinx:start
When you start the server now, an additional Windows command-line pops up with the running rake task.
Needless to say that you shouldn't add the code to script/server on your production server.

Resources