Executing Ruby script in an Rails application - ruby-on-rails

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

Related

access rails app without using http

Is it possible to interact with a rails(3) app without going though the http layer? I have some processes running locally on the server, which i'd like to be able to make some changes. Similar to what you can do in the rails console, but in a non-interactive way. I just would just call some ruby scripts to update some records in the database, rather than type them myself in the rails console.
Write these scripts you are talking about, connect via ssh and run them from the bash?!^^
ssh is the secure shell, sth. like telnet but encrytped with ssl if you are no linux user you may dont know about it...
Ahh damn and when you write thes scrips you must do this to get your applications environment:
require 'config/environment.rb'
After requireing the environment file you cann acces all your Models with the script!
If you are just trying to update a bunch of records in the DB, you don't need complete Rails installation. You can write a script and establish connection manually. Something like:
require 'rubygems'
require 'active_record'
class User < ActiveRecord::Base
establish_connection :adapter => "sqlite3", :database => "users.db"
set_table_name "users"
end
User.create(:name => 'a user', :email => 'user#example.com')
And call this from cron the way you want.
Try writing a custom rake task.
Place a file, say, task.rake in your lib/tasks directory. In that file, define a task:
task :mytask => :environment do
#code here
end
and call it from the command line:
> rake mytask

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

Rails: How to test code in the lib/ directory?

I have a model which gets its data from a parser object. I'm thinking that the parser class should live in the lib/ directory (although I could be persuaded that it should live soewhere else). The question is: Where should my unit tests for the parser class be? And how do I ensure that they are run each time I run rake test?
In the Rails application I'm working on, I decided to just place the tests in the test\unit directory. I will also nest them by module/directory as well, for example:
lib/a.rb => test/unit/a_test.rb
lib/b/c.rb => test/unit/b/c_test.rb
For me, this was the path of last resistance, as these tests ran without having to make any other changes.
Here's one way:
Create lib/tasks/test_lib_dir.rake with the following
namespace :test do
desc "Test lib source"
Rake::TestTask.new(:lib) do |t|
t.libs << "test"
t.pattern = 'test/lib/**/*_test.rb'
t.verbose = true
end
end
Mimic the structure of your lib dir under the test dir, replacing lib code with corresponding tests.
Run rake test:lib to run your lib tests.
If you want all tests to run when you invoke rake test, you could add the following to your new rake file.
lib_task = Rake::Task["test:lib"]
test_task = Rake::Task[:test]
test_task.enhance { lib_task.invoke }
I was looking to do the same thing but with rspec & autospec and it took a little digging to figure out just where they were getting the list of directories / file patterns that dictated which test files to run. Ultimately I found this in lib/tasks/rspec.rake:86
[:models, :controllers, :views, :helpers, :lib, :integration].each do |sub|
desc "Run the code examples in spec/#{sub}"
Spec::Rake::SpecTask.new(sub => spec_prereq) do |t|
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
end
end
I had placed my tests in a new spec/libs directory when the rpsec.rake file was configured to look in spec/lib. Simply renaming libs -> lib did the trick!
An easy and clean way is just to create a directory under test/unit/lib. Then create test as test/unit/lib/foo_test.rb corresponding to lib/foo.rb. No new rake tasks required, and you can nest more directories if needed to match the lib directory structure.
As of Rails 4.0:
rake test:all # Run all tests in any subdir of `test` without resetting the DB
rake test:all:db # Same as above and resets the DB
As of Rails 4.1, redefine test:run to include additional tasks when running rake or rake test:
# lib/tasks/test.rake
namespace :test do
Rake::Task["run"].clear
task run: ["test:units", "test:functionals", "test:generators", "test:integration", "test:tasks"]
["tasks"].each do |name|
Rails::TestTask.new(name => "test:prepare") do |t|
t.pattern = "test/#{name}/**/*_test.rb"
end
end
end
This has the added bonus of defining rake test:tasks in the given example.
As of Rails 4.2, test:run includes all subdirs of test including them when running rake test, and thus rake.
To not define additional rake tasks to run tests from the custom defined folders you may also run them with the command rake test:all. Tests folders structure for the lib folder or any other custom folder is up to you. But I prefer to duplicate them in classes: lib is matched to test/lib, app/form_objects to test/form_objects.
Use:
[spring] rake test:all
to run all tests, including the directories you created (like [root]/test/lib/).
Omit [spring] if tou aren't using it.

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.

RoR environment in Ruby standalone script

I want to run a standalone ruby script in which I need my RoR environment to be used. Specifically, I need my models extending ActionMailer and ActiveRecord. I also need to read the database configuration from my database.yml.
How do I go about it?
The easiest way is to change the shebang of your script from :
#!/usr/bin/ruby
to
#!/path/to/your/rails/script/runner
Et voilĂ , your script will be run with the full rails environment loaded. You can also run your script as ./my_script -e production to have it run with the production database.
Check out this thread:
How do I run Ruby tasks that use my Rails models?
Essentially it boils down to:
require "#{ENV['RAILS_ROOT']}/config/environment.rb"
Have fun!
I think the best way to do this is to make it a rake task.
# lib/tasks/mystuff.rake
desc 'do my stuff'
task :my_stuff => [:environment] do
# do my stuff
end
The [:environment] stanza loads the rails environment.

Resources