ruby on rails


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

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.

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'
        }

Today, there was an announcement about Dreamhost, having the new Passenger (mod_rails) feature ready for use with Ruby on Rails applications.
The full announcement is here.

It should be changing the way Rails applications are deployed, making it much easier.

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.

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)

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

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

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.

Problem
Upgrading from Rails version 1.2.3 to version 2.0.2.
Following the suggestion in DH’s weblog here when using sudo gem install rails -y, it gets the trunk version of rails which at the time was 2.0.2.9216.
This causes a few problems and breaks a few more things.

Solution
In order to get back to the latest stable version, you have to uninstall a few of the gems installed from the trunk version.
If you have installed the latest version of top of an existing one using gems, then doing:

gem list --local

will give you all the installed versions of the gems. Something like:

actionmailer (2.0.2.9216, 2.0.2, 1.3.3)
actionpack(2.0.2.9216, 2.0.2, 1.3.3)
rails(2.0.2.9216, 2.0.2, 1.2.3)
...

Make sure you uninstall all the gems with version number 2.0.2.9216:

sudo gem uninstall rails
sudo gem uninstall actionmailer
sudo gem uninstall actionpack
sudo gem uninstall activerecord
sudo gem uninstall activeresource
sudo gem uninstall activesupport
sudo gem uninstall rails

In each of the above commands the gem package manager should ask you to select the one you want to uninstall.
Pick the one with the 2.0.2.9216 (or other version later than 2.0.2).

At the end if you list the gems again you should only have gems going up to version 2.0.2

An extra step I had to take for making the migrations work was to install rake again:

sudo gem install rake

After all these my installation seems to be working fine again.

Next Page »