Developing in Rails 2.1 and deploying in Rails 2.0.2 (or error – undefined method time_zone)

Problem
You are developing on the latest version of Rails (2.1), but your production server for deployment uses version 2.0.2 (as dreamhost is using at the moment).

Solution

  1. First change the environment.rb file to use the rails version in your deployment server
    RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION
    
  2. You should probably be geting the error: undefined method = time zone by now, so make sure you comment out from further down your environment.rb file the line:
    config.time_zone = 'UTC'
  3. Some further errors would be caused by the file config/initializers/new_rails_defaults.rb, so make sure you comment out the following lines:
    ActiveRecord::Base.include_root_in_json = true
    ActiveRecord::Base.store_full_sti_class = true
    ActiveSupport.use_standard_json_time_format = true
    ActiveSupport.use_standard_json_time_format = true

You should be able to deploy and use your application now.

Ruby on Rails email scheduling using runner and cron

Problem
You want to send emails from a Ruby on Rails application, when there is a specific condition on a database table. If the database table gets modified by another application outside Rails you cannot use an observer model.

Solution
We already assume that:

  • You are using a database
  • You have a model named voicemail (id, number_id, audio, created_at, updated_at)
  • You have a model named number (id, voicemail_email_set, voicemail_email, ….)
  • A mail server to use (smtp in our case)
  • Another application (voice application) populates the voicemail table but with empty updated_at values

So the steps we have to follow are:

  1. Change the settings in your config/environment.rb file to use the settings for your mail server, and make sure you restart your application after the changes:
    ActionMailer::Base.smtp_settings = {
      :address        => "yourmailserver.com",
      :port           =>  25,
      :domain         => "your.domain.com",
      :authentication => :login,
      :user_name      => "your_smtp_username",
      :password       => "your_smtp_password",
      :raise_delivery_errors  => true}
  2. Create your mailer model (ie voicemail_mailer.rb), in app/models:
    class VoicemailMailer < ActionMailer::Base
       # We need the open-uri to be able to open url *** if the file to attach is in an http location ***
      require 'open-uri'
     
      def sent(email_to,email_from,email_subject,email_body,voicemail_to_send)
        # Check to see if we have a file for the email body message
        @subject    = email_subject
        @body       = email_body
        @recipients = email_to
        @from       = email_from
        @sent_on    = Time.now
        
        # Split the file in directory and filename
        file_path = File.split(voicemail_to_send)
        file_dir  = file_path[0]
        file_name = file_path[1]
        
        # Get the file
        tmp_file = open(voicemail_to_send).read
        
        part( :content_type => "application/wav", 
              :disposition => "attachment; filename=#{file_name}", 
              :transfer_encoding => "base64") do |attachment|
                attachment.body = tmp_file
        end
      end
    end
    
  3. Create your email scheduler in file lib/email_scheduler.rb:
    #!/usr/bin/env /path_to_your_app/script/runner
    
    # get all the voicemails that have not been sent yet 
    voicemails_to_email = VoiceMail.find(:all, :conditions => 'updated_at is null')
    
    # For all the voicemails we have, send them and update the field date_sent
    for vm2email in voicemails_to_email do
      # Get the number for the voicemail
      number = Number.find(vm2email.number_id)
      
      # check to see if the send to email is set for the number
      if number.voicemail_email_set
        # Get number details (email_to,email_from etc)
        email_to          = number.voicemail_email
        voicemail_to_send = vm2email.audio
        # Set other details
        email_from      = 'Service@yourdomain.com'
        email_subject   = 'Please find attached your voicemail message'
        email_body      = "Received on: #{Time.now} \n for number: #{number.phone_no}"
    
        # Now send the email
        VoicemailMailer.deliver_sent(email_to,email_from,email_subject,email_body,voicemail_to_send)
    
        # And update the record's date_sent field
        vm2email.updated_at = Time.now
        vm2email.save
      end
    end
    
  4. Create a task in your crontab that runs the scheduler (every five minutes):
    0,5,10,15,20,25,30,35,40,45,50,55 * * * * path_to_your_ror_app/lib/email_scheduler.rb

Rails 2 new ways

Problem
To get used to the new ways of working with Rails 2.

Solution
Here are some of the new ways of doing things in Rails 2.

  1. Create a scaffold and migration on one step:
    ./script/generate scaffold product fied1_name:string field2_name:string field3_name:float

    Make sure that you don’t have any previous migration(ie manually created) for the same model, as the generator will stop and won’t overwrite the previous migration.

Upgrading Ruby on Rails application from 1.2.3 to 2.0.2

Problem
Upgrading an existing Ruby on Rails application from 1.2.3, to 2.0.2, presents few problems. I will try and keep a record of the ones I encounter along the way, here.

Solution

  1. Change the config/environment.rb to let the application know to use the 2.0.2 gem rail version,
  2. change the following line from:

    RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION

    to:

    RAILS_GEM_VERSION = "2.0.2" unless defined? RAILS_GEM_VERSION
  3. Run the following to generate the secret key for the application:
  4. rake secret
  5. Copy the magic key in a new section in your config/environment.rb as in:
  6. ...
    
        # config.log_level = :debug
    
        # Your secret key for verifying cookie session data integrity.
        # If you change this key, all old sessions will become invalid!
        # Make sure the secret is at least 30 characters and all random,
        # no regular words or you'll be exposed to dictionary attacks.
        config.action_controller.session = {
          :session_key => '_yourapplication_session',
          :secret      => 'long_string_generated_from_rake_secret'
        }

ruby incorrect encoding of pound sign(£)

Problem
You want to pass the £ sign to an http service, but the ruby CGI.escape encodes it incorrectly.

Solution
After using ruby’s CGI.escape for the string as:

sms_msg_tmp=CGI.escape(sms_code)

then replace the encoding with the pound sign encoding as in:

sms_msg=sms_msg_tmp.gsub('%C2%A3','%A3')

It should then pass the correct value for the £ sign.

Disabling rails web site when using mongrel,Apache,capistrano 1.4.1

Problem
You want to disable your rails web site for maintenance, but your application uses an older capistrano version than the one currently installed.

Solution
According to the RubyOnRails Cookbook recipe 13.12, it should only be a case of running cap disable_web (enable_web).
But in the meantime you have upgraded your capistrano version to version 2, and started using mongrel server as well.
So if you are using virtual severs and proxy with mongrel, the first thing to do is add the following in your Apache configuration file:

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [R]

If you needed to make the above change then you will have to restart apache in your server.

Then in your local pc you can run the following:

export REASON="Maintenance for MySQL upgrade"
export UNTIL="Sat May 10 15:30:00 2008"
cap _1.4.1_ disable_web (to put it in maintenance)
cap _1.4.1_ enable_web (to restart it again)

git: fatal error: `chdir’ failed: permission denied.

Problem
Trying to use the heroku gem to clone a project and do local modifications I got the following error:

git: fatal error: `chdir' failed: permission denied.

Solution
It turns out that in Mandriva, when using:

sudo urpmi git

what gets installed is the ‘GNU Interactive Tools’ that has nothing to do with the git version control system.
So make sure you first uninstall the git installed:

sudo rpm -e git

and then install the Git – Fast version control system, by doing:

sudo urpmi git-core

You should then be able to clone a heroku application:

heroku clone myapp

Ext.ux.grid has no properties error

Problem
Trying to use ExtJS with RubyOnRails on Heroku, gives the following error and a blank page in Firebug.

Ext.ux.grid has no properties
...
Line 141

Solution
In Heroku, you will probably have to manually upload the files from the ExtJS library, as well as the ext_scaffold plugin.
When you do that, two files that ext_scaffold needs, and which they should be located in ext_scaffold/assets/javascripts should be copied to public/javascripts.
The files are:

ext_datetime.js
ext_searchfield.js

Installing sqlite3-ruby in Mandriva and Rails 2.0.2

Problem
After upgrading to Rails 2.0.2 when trying to install the sqlite3-ruby gem got the following error:

ERROR:  Error installing sqlite3-ruby:
ERROR: Failed to build gem native extension.
/usr/bin/ruby extconf.rb install sqlite3-ruby
checking for sqlite3.h... no
make
make: *** No rule to make target `ruby.h', needed by `sqlite3_api_wrap.o'.  Stop.
Gem files will remain installed in /usr/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.2.1 for inspection.
Results logged to /usr/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.2.1/ext/sqlite3_api/gem_make.out

Solution
In Mandriva you need to install the ruby-sqlite3 and the development libraries first, like:

sudo urpmi ruby-sqlite3
sudo urpmi libsqlite3-devel

After that you should be able to install the gem as normal.