Archive for May, 2008

Rails background process - simple, fast, easy.

My situation was this -

  • Rails 2.0 app running on slicehost (ubuntu 8.04) in passenger mod_rails
  • The goal was Dynamic PDF generation for a product catalog ( > 100 pages)
  • This event had to be triggered from within the rails request / response cycle, but run outside of it
  • I needed the simplest, fastest, more reliable way for this to happen

I looked at BackgroundRB, it is the most robust, well documented solution available.  But it was overkill since I didn’t need status feedback and my time was very limited (backgroundRB setup seems somewhat involved).  And, I wasn’t sure how it would interact with Passenger mod_rails - although FooBarWidget mentioned on IRC that it should work as expected.

I looked at Spawn plugin which supports threading and forking ruby processes.   No luck - setting it one way never ran inside mod_rails and setting it the other way tied up the request response cycle.

All the ruby code was in place, except for how to detach this process from the request/response cycle, when severnspoon provided this
Simple, Easy, One-Line Solution:

My_Controller
  def generate_pdf_in_background
    system " RAILS_ENV=#{RAILS_ENV}   ruby  #{RAILS_ROOT}/script/runner   'MyModel.create_pdf_in_background'  &
  end
end

That ampersand was all I needed.  It runs the command as a background process.  A new ruby process is kicked off, and the 10 minute task runs perfectly.  Something makes the browser hang and wait for a response, but we confirmed that other requests can happen along side this.

Point

 
icon for podpress  Point: Play Now | Play in Popup | Download (15)

mod_rails set RAILS_ENV variable to QA, Staging, or Production

I’m using mod_rails with capistrano and multi-stage (qa, staging, production), and wrote this workaround so that the RAILS_ENV could be set correctly in each stage.  Mod_rails sets RAILS_ENV once in the global server conf file, but I needed it set once for each environment: qa, staging, and production.  I tried setting ENV['RAILS_ENV] in each file under config/deploy/ but the setting was not picked up.

Solution - write the correct value into config/environment.rb’s  ENV[''RAILS_ENV] while deploying.

So here is my 3 step fix -

Step 1.

I created a new file

lib/set_mod_rails_env.rb

# sets ENV['rails_env'] for mod_rails
# http://www.megasolutions.net/ruby/search-a-file-and-replace-text-50116.aspx
# Robert Evans'
def ChangeOnFile(file, regex_to_find, text_to_put_in_place)
  text = File.read file
  File.open(file, 'w+'){|f| f << text.gsub(regex_to_find,
      text_to_put_in_place)}
end
ChangeOnFile("#{ARGV[0]}/config/environment.rb”, /#mod_rails_env_here/, “ENV['RAILS_ENV']=’#{ARGV[1]}’”)

Step 2.

Add the following code to config/deploy.rb

namespace :deploy do
desc "set ENV['RAILS_ENV'] for mod_rails”
task :before_restart do
run "ruby #{current_release}/lib/set_mod_rails_env.rb  #{current_release}  #{stage}"
end
end

Step 3.

Add the following code to config/environment.rb

# deploy.rb will swap this out for the appropriate rails_env.
# mod_rails apparently need this var in this file (not ./environments/qa.rb)
# do not change the following line. Ruby regexp looks for it.
#mod_rails_env_here

That’s it.  Let me know if you know of an easier way.

jQuery validation with Prototype

Here is the jQuery validation plugin fixed up so that it works if you have prototype installed along side jQuery.  I just replaced references to $() with jQuery() in the jQuery.validations.js file.
jquery.validate.js with prototype