Run Rails commands outside of console - ruby-on-rails

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

Related

Google App Engine: Ruby on Rails - Execute migrations automatically

I was wondering if it was possible to run migrations automatically during deployment with Google App Engine. I have been using AWS Elasticbeanstalk for a while and they were ran automatically but now I am considering moving to the Google App Engine for my future projects.
Right now, I must run this command manually:
bundle exec rake appengine:exec -- bundle exec rake db:migrate GAE_CONFIG=app.yml
Thank you
WARNING: As discussed in comments, there is a race condition in migrations if deployment is done on multiple containers in parallel, because it will try to run migration on all containers. Solution is being discussed in comments, i will update this answer when we land on something.
Disclaimer: This answer is not exactly what was asked for, but it solves same problem and it works. And from what i can tell from question, doing it with some appengine config is not a requirement, rather he just want the migrations to run automatically.
I will expand on my comment on question, here is something i tried and it works. I am strong believer of KISS(keep it simple and stupid). So instead of trying to figure out appengine(which i have never used anyway) if i were you, i would take a generic approach. Which is, to plug into rails server booting process and trigger migrations. For this we have multiple approaches.
With my understanding of appengine and suggested by this official doc link appengine has a app.yaml file, this file has an entry something like:
entrypoint: rails server
So we will use this entry point to plug in our code to run migrations before starting server. For this i did this:
Make a new file in bin directory, i named it
rails_with_migrations.sh you can name it whatever you like.
Give it execute permissions with chmod +x bin/rails_with_migrations.sh
Put this code inside it:
#!/bin/bash
bundle exec rake db:migrate
bundle exec rails $#
Of course you can give whatever RAILS_ENV you want to give these.
Now in app.yaml on the entrypoint section, instead of rails server give it bin/rails_with_migrations.sh server and it should be it. It worked on local, should work everywhere.
NOTE: In entrypoint: i have bin/rails_with_migrations.sh server here, server is rails command parameter, you can pass as much parameters as you like these all will be passed to rails server command with $#'s magic. It is there to allow you to pass port and any other parameters you may need to provide for your environment. Also it allows you to run rails console locally with bin/rails_with_migrations.sh console which will also cause migrations to get triggered.
UPDATE1: As per comment, i checked what happens if migration fails, and it starts server even if migration fail. We can alter this behavior of-course in our sh file.
UPDATE2: The shell-script with migration error code handling will look something like:
#!/bin/bash
bundle exec rake db:migrate
if [ $? -eq 0 ]
then
bundle exec rails $#
else
echo "Failure: migrations failed, please check application logs for more details." >&2
exit 1
fi
This update will prevent server from starting and causing a non zero exit code from the script, which should indicate that this command failed.

Running node.js code from Rails application

I am trying to integrate some node.js code with my Rails application. Basically its a js file with some code that process will keep running in background.
I have followed the following steps:
Added code in root of rails app in some test_node.js file.
Now what I do is pass a value to my system using exec function of ruby, e.g exec "node test_node.js".
This works perfectly fine but it chop my server from processing any requests.
To pass it to background i tried using nohup e.g: exec "nohup node test_node.js".
When I run this code my server crashes.
I am Rails developer and never worked on node app so have no idea if I taking it right way or not.
exec replaces the currently running process with a new one. Thus, to run something in the background you should fork and exec in the child.
fork { exec('node', 'test_node.js', ...) }
nohup is not needed.
See also Ruby, Difference between exec, system and %x() or Backticks

Running Rails Task From Cron

I have a Rails runner task that I want to run from cron, but of course cron runs as root and so the environment is set up improperly to get RVM to work properly. I've tried a number of things and none have worked thus far. The crontab entry is:
* 0 * * * root cd /home/deploy/rails_apps/supercharger/current/ && /usr/local/rvm/wrappers/ruby-1.9.3-p484/ruby bundle exec rails runner -e production "Charger.start"
Apologies for the super long command line. Anyhow, the error I'm getting from this is:
ruby: No such file or directory -- bundle (LoadError)
So ruby is being found in the RVM directory, but again, the environment is wrong.
I tried rvm alias delete [alias_name] and it seemed to do something, but darn if I know where the wrapper it generated went. I looked in /usr/local/rvm/wrappers and didn't see one with the name I had specified.
This seems like a common problem -- common enough that the whenever gem exists. The runner command I'm using is so simple, it seemed like a slam dunk to just put this entry in the crontab and go, but not so much...
Any help with this is appreciated.
It sounds like you could use a third-party tool to tether your Rails app to cron: Whenever. You already know about it, but it seems you never tried it. This gem includes a simple DSL that could be applied in your case like:
every :day # Or specify another period, or something else, see README
runner "Charger.start"
end
Once you've defined your schedule, you'll need to write it into crontab with whenever command line utility. See README file and whenever --help for details.
It should not cause any performance impact at runtime since all it does is conversion into crontab format upon deployment or explicit command. It's not needed, once the server is running, everything is done by cron after that.
If you don't want an extra gem anyway, you might as well check what command does it issue for executing your task. Still, an automated way of adding a cron task is easier to maintain and to deploy. Sure, just tossing a line into the crontab is easier — just for you and just this once. Then it starts to get repetitive and tiring, not to mention confusion for other potential developers who will have to set up something similar on their own machines.
You can run cron as different user than root. Even in your example the task begins with
* 0 * * * root cd
root is the user that runs the command. You can edit it with crontab -e -u username.
If you insist on running cron task as root or running as other user does not work for some reason, you can switch user with su. For example:
su - username -c "bundle exec rails runner -e production "Charger.start"

Start Rails server from within Rails

Is it possible to start a rails server from within a running rails server?
I would also like to install the gems using 'bundle install'.
I made a simple setup, but when i invoke 'bundle install', the gems from the running rails server are installed and not the gems for the server i wish to start.
What would be the best strategy to launch another rails server.
As others have stated in the comments, you can spawn shell commands from your Rails application. You have several options. http://mentalized.net/journal/2010/03/08/5_ways_to_run_commands_from_ruby/
If you want to inherit the user environment when running bundle commands, you might want to spawn a bash login shell then run the command. E.g. ```/bin/bash -l -c "command here".
Although you didn't ask about killing them, if you're only going to run this and you're not building anything to keep track of process IDs, you could find and kill other instances with some ps aux | awk '/process name or unique path/ {print $2}' | xargs kill magic

Expose Rails App Environment to Ruby Script

Out of pure curiosity, I am wondering if it's possible (no doubt it is) to 'hook into' a Rails Application's environment. So for example, say I want to create a cron script (I don't) that operates some sort of maintenance on a Rails app, and I want to write it in Ruby and using all of the nice code that I already have, for example, User.find etc.
Is this possible, and if so, how?
I'm just curious, as I feel I would eventually want to do this for some reason or other.
I'm currently on Rails 3 with Ruby 1.9.1, in case it matters.
This is certainly possible. Here is a good writeup on how to do that: How to run a rake task from cron
Take a look at the Rails::Railtie class. If you need to run code code when you start up your app, this is a way to do it. Here's a very simple example.
From the beginning of Rails there is ./script/runner, designed exactly for such kind of problems.
In Rails 3 you call it as: ./script/rails runner "puts User.find(:all).map(&:inspect)"
Try ./script/runner --help or ./script/rails runner --help
As the argument to the runner you provide a filename or just a code.
It's often more useful than preparing a Rake task, because you can execute just one-time actions:
ssh prod#example.com "cd rails/app && ./script/runner -e production 'puts User.count'"
You could either use script/rails runner as suggested by Arsen7 or you could write your own script in which you load the app environment in the beginning:
require 'config/environment'
is actually everything you need.
To have your script working in a cron job, make sure that it is executable (chmod u+x) and that it starts with a correct shebang line (#!/usr/bin/env ruby or whatever is appropriate for your situation).
yeah just require these file at top of your script file
require 'config/boot.rb'
require 'config/application.rb'
Rails.application.require_environment!
Now you'll have access to your models

Resources