How can I boot Rails 3 in a daemonized ruby script? - ruby-on-rails

I am pulling email via pop into my Rails 3 application so i have a file called dropbox_receiver.rb in the rails lib directory.
This pulls in all email and calls DropBox.receive(email)
I can run this using rails/runner but when i run it from the daemon_controller.rb file i get the error
initialized constant Object::DropBox
How do i boot rails 3 in this script ?
Also how do i log properly from this script to my production.log?

Put this at the top of your script:
ENV['RAILS_ENV'] = ARGV.first || ENV['RAILS_ENV'] || 'development'
require File.expand_path(File.dirname(__FILE__) + "/../../config/environment"
That's for a script in app/controllers. You'll need to adjust the path to config/environment if your daemon is elsewhere.

Also, you're probably going to run into the issue of open files as described here.

Related

How add ruby file to Rails application and make it auto-loadable/executable on Rails app start?

I am trying to add some external non-rails services to my JRuby Rails application (from another framework).
I want to run a Ruby file in the context of my Rails Application and make it auto-loadable/executable on Rails app start.
I didn't find the answer on Stackoverflow yet, the closest I have found so far is the suggestion to use rake tasks.
But i want it to be something like this:
In my
/app
directory besides controllers, models, views folders
I want to have something like:
/app/services
and in this services folder to have some
service_a.rb
service_b.rb
service_c.rb
so that when I start the Rails application, RAILS autoload those files from /services folder and executes them.
I have read this http://guides.rubyonrails.org/autoloading_and_reloading_constants.html
But it didn't help, it was just naming conventions and name space constants.
I want to have in my rails app something like entrypoint (like in C / Java) from where I load and execute some additional logic, that doesn't belog to rails (Vertx.io verticles deployment)
or to have some app.rb "main Class, method" from where I would load my /services and execute them
# app.rb
require 'vertx/vertx'
vertx = Vertx::Vertx.vertx()
# deploy verticles or vertx.deploy_verticle("verticles/myverticle.js")
puts " ##### I am about to deploy verticles! "
vertx.deployVerticle("verticles/listener.rb")
puts " verticle listener.rb has been deployed i think"
vertx.deployVerticle("verticles/sender.rb")
puts " verticle sender.rb has been deployed i think"
UPDATE
thank you for suggesting the configs of application.rb
I have just configured it the way you suggested:
# /config/application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(*Rails.groups)
module Workspace
class Application < Rails::Application
config.active_record.raise_in_transactional_callbacks = true
config.autoload_paths += Dir["#{config.root}/app/services/*"]
end
end
Then I have created the directory /app/services
Placed 2 files in there: service_a.rb and service_b.rb
I just want to make sure that the code in service_a.rb gets exectued.
So that I for example print stuff out to console.
My service_a.rb:
# service_a.rb
puts "Service A has been exectued FROM PUTS method from services/service_a.rb "
class ServiceA
def service_a_method
puts " Service_A_METHOD has been exectued from services/service_a.rb ServiceA CLASS "
end
end
def stand_alone_service_a_method
puts " stand_alone_service_a_method has been just exectued !!! "
end
stand_alone_service_a_method()
Then i go ahead and run bin/rails server
(I am using C9.IO cloud 9 web IDE and ubuntu container with rails 4.2)
javajedi:~/workspace $ bin/rails s
=> Booting WEBrick
=> Rails 4.2.5 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2017-03-25 16:07:25] INFO WEBrick 1.3.1
[2017-03-25 16:07:25] INFO ruby 2.3.0 (2015-12-25) [x86_64-linux]
[2017-03-25 16:07:25] INFO WEBrick::HTTPServer#start: pid=2413 port=3000
but as you see, nothing gets printed out to console. Is that that i haven't set up ENV to be DEV so that it allows that stuff to be printed in console?
I just wanna be sure that my code gets exectued.
Because I am gonna deploy Vertx.io Verticles via such small services files.
Please advice what do I do wrong?
You need to add the sub directory in application.rb
config.autoload_paths += Dir["#{config.root}/app/services/*"]

Rails is continually running in test mode

After upgrading to rails 2.3.5 I got things working again and the tests were passing. Then all of a sudden when I run the script/server command it now always runs in Test mode which is seen by a simple > puts RAILS_ENV
I have restarted my machine as well as run the script/server command manually setting the environment via -e, but still have no luck.
Does anyone have any idea what the cause of this would be?
** I should note that even when the RAILS_ENV constant is shows up as "test", the database config that is used is the development.
update
by adding puts RAILS_ENV statements throughout the code I can see that when I add a puts outside the Rails::Initializer.run do |config| block within the environment.rb class that at that point the RAILS_ENV becomes set to "test". Right before the end of the block it is still set to development.
The reason for the environment change was that, without thinking, I loaded the rspec gem in the development.rb file.

Executing Ruby script in an Rails application

I can run the following commands in the console for my Rails application and import CSV file into my database.
require 'csv'
# row will be an array with the fields in the order they appear in the file
CSV.open('myfile.csv', 'r') do |row|
# assuming the fields in the CSV file are in order npa, nxxFrom, nxxTo, trnk
# create and save a Trunk model for each row
Trunk.create!(:npa => row[0], :nxxFrom => row[1], :nxxTo => row[2], :trnk => row[3])
end
However I'd like to facilitate the process by just creating a script for it. The problem is I don't know how to write a script that is application specific. In order for the above commands to run, I need to launch console in the application folder by the following:
ruby script/console
So simply copy/pasting the commands into an .rb file and executing won't work.
Any help will always be appreciated :)
Why not use script/runner "<code or filename here>? to run the script? The runner script executes the script in the give application context without having a console.
You could make it a rake task which inherits from environment. Place it into lib/tasks/your_task.rake:
task :your_task => :environment do
# code goes here
end
Then run it using rake your_task. It can be called anything you want.
You need to invoke the rails environment in the script.
Try adding this at the top of you file:
RAILS_ENV = ARGV[0] || "production"
require File.join(File.dirname(__FILE__), *%w[.. config environment])
# assumes script is placed one level below the root of the application
# second parameter is the relative path to the environment directory of your rails app

Rails Daemon stays in development mode

I have a Rails application with a daemon that checks a mailbox for any new emails. I am using the Fetcher plugin for this task. The daemon file looks like this:
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment.rb'
class MailFetcherDaemon < Daemon::Base
#config = YAML.load_file("#{RAILS_ROOT}/config/mail.yml")
#config = #config['production'].to_options
#sleep_time = #config.delete(:sleep_time) || 20
def self.start
puts "Starting MailFetcherDaemon"
# Add your own receiver object below
#fetcher = Fetcher.create({:receiver => MailProcessor}.merge(#config))
...
So I have it grab the new emails, parse them and create a resource from the parsed data. But when it tries to save the resource an exception is thrown. This is because the script is automatically assigned the development environment. So it is using my development database configuration instead of the production environment (which is the config that I want).
I have tried starting the script with:
rails-root$ RAILS_ENV=production; script/mail_fetcher start
but to no avail. It seems like when I load the environment.rb file it just defaults to the development environment and loads development.rb and the development database configuration from database.yml.
Thoughts? Suggestions?
Thanks
This is working in my app, the only difference I see is no semi-colon
RAILS_ENV=production script/mail_fetcher start
So when you say
RAILS_ENV=production; script/mail_fetcher start
do you mean
#!/bin/bash
export RAILS_ENV=production
cd /path/to/rails_root
./script/mail_fetcher start
You might try adding this to your script:
ENV['RAILS_ENV'] = "production"
Alternatively, it might work to add it to the command line.
#!/bin/bash
cd /path/to/rails_root
./script/mail_fetcher start RAILS_ENV=production

How can I set the Rails environment for my somewhat stand alone Ruby script?

I have a Ruby script in my Rails app that I use to load some data from Twitter.
In the future I will make it an automatic background process, but for now I run it manually like:
ruby /lib/twitter/twitterLoad.rb
In order to use the Rails model classes and such, I have the following as the top line of the script:
require "#{File.dirname(__FILE__)}/../../config/environment.rb"
By default, the development environment is used. But, I'd like to be able to choose the production environment at some point.
Update #1: The RAILS_ENV constant is getting set in the environment.rb file. So, I was able to put ENV['RAILS_ENV'] = 'production' at the very top (before the environment.rb) line and solve my problem somewhat. So, my new question is, can do pass in env vars through the command line?
If you're going to be using the rails environment, your best bet would be to make this a rake script. To do this, put a twitter.rake file into lib/tasks and begin and end it like this:
task(:twitter_load => :environment) do
# your code goes here
end
That way, you're doing it by "following conventions" and it doesn't have that 'orrible smell associated with it.
I currently use the following method, and I know the environment doesn't have the rb extension, it's not needed. You can also set it before running it to overwrite the ENV["RAILS_ENV"].
#!/usr/bin/env ruby
# Set your environment here.
ENV["RAILS_ENV"] ||= "production"
require File.dirname(__FILE__) + "/../../config/environment"
puts "Rails was loaded!"
Then to change the environment, just run it with:
rb /lib/tasks/file.rb RAILS_ENV=development
Don't forget script/runner.
Set your environment variable from the command line and
ruby script/runner your_script_here.rb
The accepted answer to use rake is well-taken, but you may still want to manually set the environment for testing utility classes.
Here's what I use to set up the test environment for utility classes in /lib. For these I tend to use the Ruby convention of making my class file execute its tests when it gets run from the command line. This way I can do TDD outside of Rails' web-centric test harnesses, but still use the class within rake without affecting the environment that it sets.
This goes at the top:
if (__FILE__ == $0)
ENV['RAILS_ENV'] ||= 'test'
require File.join(File.dirname(__FILE__),'../config/environment.rb')
end
and this goes at the bottom:
if (__FILE__ == $0)
require 'test/unit/ui/console/testrunner'
Test::Unit::UI::Console::TestRunner.run(MyClassTest)
end
You can also do
script/console development < path/to/your/script.rb
Admiteddly cumbersome -and will spit out lots of irb garbage after evaluating each and every line of your script- but works for quickies and you dont have to remember that damned require line.
And don't forget that maybe the most elegant way to extend your app with scripts that do useful things is writing Rake tasks!
add the line:
RAILS_ENV = '<your environment of choice>'
http://wiki.rubyonrails.org/rails/pages/Environments#script
pantulis: It's cool that that works, but for quickies I just use RAILS_ENV = '<your environment of choice>' ruby path/to/script.rb. This is how you set environment variables in the console.
require 'bundler'
require 'bundler/setup'
ENV['RAILS_ENV'] ||= 'development'
RAILS_ROOT = Pathname.new(File.expand_path('~/path/to/root'))
puts "Loading Rails Environment from #{RAILS_ROOT}..."
require RAILS_ROOT.join('config/environment').to_s
This works but only if the Gemfile of your script contains all the dependencies of your rails app. You might be able to load one Gemfile from another, e.g just eval it, to overcome this copy/paste.

Resources