views:

202

answers:

2

I'm writing an app that will run scripts in a specified folder, and then record the numbers and graph them.

My problem is that if the script is a ruby file, the require statements fail inside the script because bundler seems to have done something funky with the load path.

Running rails runner Datasource.run_jobs fails:

class Datasource < ActiveRecord::Base
  def self.run_jobs
    require 'aws_sdb'
    access_key_id = "REDACTED"
    secret_key = "REDACTED" # In all actuality these woudln't be here.
    @sdb = AwsSdb::Service.new(:access_key_id => access_key_id, :secret_access_key => secret_key)

    Datasource.all.each do |ds|
      puts "Updating #{ds.name}..."
      unless @sdb.list_domains.include? ds.name
        puts "#{ds.name} doesn't exist in SDB, creating a domain for it..."
        @sdb.create_domain ds.name
      end

      #data = "TEST"
      data = `#{RAILS_ROOT}/lib/plugins/#{ds.name}`

      @sdb.put_attributes(ds.name, Time.now.to_i, data)
      puts "Data Collected: #{data.inspect}"
    end
  end

  has_many :graphs

end
+2  A: 

(Basing this off your comments on the question)

You will need to add hpricot (and any other gem this needs) to your Gemfile so that they are made available by Bundler. Bundler is by far the easiest way to avoid gem conflicts and tomfoolery.

Imagine this situation: You somehow lose the gems that you have currently. Be this happening through a format or system change or any other reason. Whatever it is, you've lost your gems. How are you going to re-install all your gems? You could keep a list of them somewhere else yourself, but is this truly likely?

Bundler solves this problem by making you state what gems your application requires and only adding those gems to the load path, which is why you can't find hpricot. When you run bundle install the first time, this creates a Gemfile.lock which contains something like this:

GEM
  remote: http://rubygems.org/
  specs:
    abstract (1.0.0)
    actionmailer (3.0.0)
    ...

Because you commit this file to your source control "solution" of choice (be it Git, SVN, FTP, whatever, it's not important) you have a solid way of specifying the precise gems and precise versions of those gems that your application uses.

When/If your gems are wiped, you can simply clone your project again and run bundle install. Because the Gemfile.lock file exists, you'll have exactly the same gems you had originally, even if there were updates.

If you don't want the exact same gems, just run bundle update and this will ignore the specifications in Gemfile.lock and instead revert to depending on Gemfile to define them. This will check for new versions of gems and install them, updating the Gemfile.lock when it's done.

Honestly, I don't understand the Bundler hate. If you could explain in wider terms than "OMG IT SUCKS YEHUDA IS SATAN", I'd be much obliged.

Edit: WedTM asked for a sample Gemfile and related code:

In the Gemfile you'd have this:

group(:scripts) do
  gem 'gem1'
end

To require these gems for your scripts:

require 'bundler'
Bundler.require(:scripts)

You may also wish to require the default gems too which you can do by just adding default anywhere to the arguments of require:

Bundler.require(:default, :scripts)

If this for some reason doesn't work I would imagine it would be because it can't locate the Gemfile. This can be fixed by setting the ENV['BUNDLE_GEMFILE'] to the path to the Gemfile.

Ryan Bigg
Ryan, I really like that part of bundler, it DOES make it easier! However, I think the part that your failing to see in my problem, is that the file that is being run is NOT part of my rails app. It's just a script on the system that resides in a folder. I happen to have my rails app loop through EVERY file in that folder, and record it's output. If I run the file OUTSIDE of my rails app, it works as expected, but running it in the context of the app (rails runner 'Method.containing_a_call_to_said_script' it fails.
WedTM
@WedTM: Then require Bundler, point it at your Gemfile and then put the script gems in a group called "script" and include them using Bundler.require(:script)?
Ryan Bigg
Ryan, the question and a huge thank you are in it for you if you could give me an example.
WedTM
@WedTM: Updated. Give that a go.
Ryan Bigg
Ryan, I'm still missing the point that I DON'T want to use the Gemfile. I'd like people to upload/edit scripts in my app. These scripts are written using Ruby. During cron, I want to run those scripts in that directory.
WedTM
@WedTM (first comment): If you're running them from within the Rails environment (ie, with script/runner, which requires config/environment.rb), then they're a part of your rails app. But seeing as how others are submitting them, I think your approach in the original question, using backticks, is the correct way to go. I presume you only spoke of script/runner as an _example_ of running the scripts within your app, since you had it them _external_ to your app in the original question. I'll report more if I learn anything about bundler changing the load paths of system calls.
Tim Snowhite
A: 

I wonder if you might be able to use RVM to set up the ruby environment before running your scripts. Maybe something with a gemset like:

data = `rvm gemset use scripts; #{RAILS_ROOT}/lib/plugins/#{ds.name}`
Andrew Vit