eXpand yOur cReativity by Bhushan G Ahire

17Feb/100

Setup Capistrano to deploy Rails application on Amazon EC2 with Git

1: Create a new Rails app - we'll call is 'deploytest'

$ rails deploytest
$ cd deploytest

2: Create a local Git repository for it

$ git init
$ git add *
$ git commit -a -m 'initial commit'
$ git status

3: Create a couple of Capistrano files

$ capify .

4: Edit config/deploy.rb

# The name of your app
set :application, "deploytest"
# The directory on the EC2 node that will be deployed to
set :deploy_to, "/var/www/apps/#{application}"
# The type of Source Code Management system you are using
set :scm, :git
# The location of the LOCAL repository relative to the current app
set :repository,  "."
# The way in which files will be transferred from repository to remote host
# If you were using a hosted github repository this would be slightly different
set :deploy_via, :copy

# The address of the remote host on EC2 (the Public DNS address)
set :location, "ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com"
# setup some Capistrano roles
role :app, location
role :web, location
role :db,  location, :primary => true

# Set up SSH so it can connect to the EC2 node - assumes your SSH key is in ~/.ssh/id_rsa
set :user, "root"
ssh_options[:keys] = [File.join(ENV["HOME"], ".ssh", "id_rsa")]

The only account on a default EC2 instance is root. You probably want to create a second user that is responsible for your application.

5: Copy your SSH public key to your EC2 node

$ scp -i ~/my-ec2-keypair ~/.ssh/id_rsa.pub root@ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com:/root/.ssh/authorized_keys2

NOTE the filename authorized_keys2 - not authorized_keys!!

6: Setup the EC2 node for Capistrano deployment.
From your LOCAL machine, not the EC2 node:

$ cap deploy:setup

7: Finally, deploy your application

$ cap deploy

You will see lots of output and with this dummy application some of those will report errors/warnings. Don't worry about that for now.

8: Check that the Deployment was successful
Connect to the EC2 node with SSH the regular way, cd to the app directory and check that everything is there. If that is all working then you are ready to deploy a real application and add custom tasks for managing the database, restarting the server etc.

Bear in mind that Capistrano add new 'releases' of your software in separate directories and symlinks the 'current' directory to the latest. So the root of your deployed application is the 'current' subdirectory.

Hope this will help you setting up your ec2 instance with capistrano.

15Jan/100

Send SMS from Ruby On Rails application using web service, SOAP API

SOAP4R is a Ruby library for accessing Web Services via SOAP. Recently I had a chance to explore SOAP4R. Here's how to get started with it.

Installation

Although Ruby 1.8.x comes with SOAP4R in its standard library, it is an old, buggy version. I highly recommend using the latest gem (1.5.8 as of the this update). It has one dependency, httpclient.

gem install soap4r --include-dependencies

Service

There are many services available to send SMS but I prefer to use,

MailServe-SMS

MailServe-SMS, text messaging service, is everything you need for fast, no-frills, no-fuss text messaging. A quick and easy way to send SMS.

Let’s explore these further.

Method 1: Read the WSDL at run-time

 

require "soap/wsdlDriver"
wsdl = "http://sms.qlc.co.in/smsapi.wsdl"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_drive

 

A single call to a driver factory reads the WSDL file, and creates a driver class for you to use, complete with the methods defined by the service. What if your service requires authentication? The driver inherits methods from httpclient, so you can specify its options as you would for httpclient:

Once driver is get initialised you need to call SMS sending API i.e. SendSMSRequest.

driver.SendSMSRequest("username", "password", "sender_no", "from_no", "message")

 

Once This will return you response 200 SMS sent successfully on success else if the information submitted was wrong then 500 Information submitted was incomplete.

 

Method 2: Generate classes from WSDL

SOAP4R installs a command-line utility called 'wsdl2ruby' which can generate a client or server.

Coming soon…..

5Aug/093

Paypal Instant Payment Notification in Rails with Active Merchant

Active Merchant makes it extremely simple to use Paypal IPN. Here is a simple guide for getting IPN up and running.

Sign up for a Paypal sandbox account

Paypal provides a sandbox environment that mimics their production environment, with the exception that it doesn’t actually process the transactions. This is extremely useful for development and testing. It allows you to create multiple fake accounts and generate bank accounts and credit cards. More information can be found on Paypal’s Testing Instant Payment Notification page.

Unfortunately, I’ve signed up for two different developer accounts and I’ve had trouble logging in with both of them. I’ve tried resetting my password, but I still can’t log in. Fortunately, I already have my sandbox accounts set up and don’t really have a need for it (except to write this guide).

Create a Personal account and add a credit card

After you sign up for your developer account, create a personal sandbox account and add a credit card.

Create a Business account and add a checking

Next, create a business sandbox account and add a checking account.

Install the money gem

sudo gem install money

Install the Active Merchant plugin

script/plugin install http://activemerchant.googlecode.com/svn/trunk/active_merchant

Create a form that submits to Paypal

Include ActiveMerchant::Billing::Integrations in a controller to add Active Merchant’s helpers.

class PaymentsController < ApplicationController
  include ActiveMerchant::Billing::Integrations

  def create
    @enrollment = current_user.enrollments.find(params[:id])
  end
end

In the view, use payment_service_for to create a form that submits to Paypal to process the payment.

<% payment_service_for @enrollment.id, PAYPAL_ACCOUNT,
        :amount => @enrollment.course.deposit, :currency => 'USD',
        :service => :paypal do |service|

    service.customer :first_name => @enrollment.student.first_name,
        :last_name => @enrollment.student.last_name,
        :phone => @enrollment.student.phone,
        :email => @enrollment.student.email
    service.billing_address :city => @enrollment.student.city,
        :address1 => @enrollment.student.street,
        :state => @enrollment.student.state,
        :country => 'USA',
        :zip => @enrollment.student.zip
    service.item_name "#{@enrollment.course.program} Deposit"
    service.invoice @enrollment.invoice.id
    service.tax '0.00'

    service.notify_url url_for( :o nly_path => false, :action => 'notify')
    service.return_url url_for( :o nly_path => false,
        :controller => 'account', :action => 'show')
    service.cancel_return_url url_for( :o nly_path => false,
        :controller => 'account', :action => 'show') %>

    <!-- display payment summary here -->

    <%= submit_tag 'Make Payment' %>
<% end %>

The code above refers to the constant PAYPAL_ACCOUNT, which I define in environment.rb. I also set Active Merchant to use test mode, which directs it to use Paypal’s sandbox:

unless RAILS_ENV == 'production'
  PAYPAL_ACCOUNT = 'sandboxaccount@example.com'
  ActiveMerchant::Billing::Base.mode = :test
else
  PAYPAL_ACCOUNT = 'paypalaccount@example.com'
end

Create an action that processes the IPN

After the above form submits to Paypal and the user makes a payment, Paypal will post data about the transaction to your server. Set up an action to receive the post:

  def notify
    notify = Paypal::Notification.new(request.raw_post)
    enrollment = Enrollment.find(notify.item_id)

    if notify.acknowledge
      @payment = Payment.find_by_confirmation(notify.transaction_id) ||
        enrollment.invoice.payments.create(:amount => notify.amount,
          :payment_method => 'paypal', :confirmation => notify.transaction_id,
          :description => notify.params['item_name'], :status => notify.status,
          :test => notify.test?)
      begin
        if notify.complete?
          @payment.status = notify.status
        else
          logger.error("Failed to verify Paypal's notification, please investigate")
        end
      rescue => e
        @payment.status = 'Error'
        raise
      ensure
        @payment.save
      end
    end
    render :nothing => true
  end

Depending on the model for your application, this action will obviously look different. The important part is that you pass the raw post data from the request to Paypal::Notification.new, and call notify.acknowledge to connect back to Paypal to verify the data.

Enable IPN

Lastly, log into the business account that you created above, go to “Instant Payment Notification Preferences” in your profile, and set the URL that Paypal should post back to after payments. (Note: this needs to be a publicly accessible URL.)

20May/090

Get location from IP address in Ruby On Rails for free….

Find below the code for finding location from IP address using IP location tools.

require 'net/http'
require 'rexml/document'
include REXML

class MapsController < ApplicationController
	def index
		@location = locateIp()

	end

	def locateIp
		ip = request.remote_ip
		ips = ip.to_s
		url = "http://iplocationtools.com/ip_query.php?ip="+ips

		xml_data = Net::HTTP.get_response(URI.parse(url)).body

                xmldoc = REXML::Document.new(xml_data)

		# Now get the root element
		root = xmldoc.root
		city = ""
		regionName = ""
		countryName = ""

		# This will take country name...
		xmldoc.elements.each("Response/CountryName") {
		|e| countryName << e.text
	    }

		# Now get city name...
		xmldoc.elements.each("Response/City") {
   		|e| city << e.text
	    }

		# This will take regionName...
		xmldoc.elements.each("Response/RegionName") {
   		|e| regionName << e.text
	    }

     	ipLocation = city +", "+regionName+", "+countryName

	 return ipLocation
   end #end of method locateIp

end
3Mar/090

Generating ZIP files via Ruby on Rails using rubyzip

gem install rubyzip

Then, in the model that I’m using to generate the zip bundles, I add a couple “require” statements:

require 'zip/zip'
require 'zip/zipfilesystem'

class Album < ActiveRecord::Base
  (...)
end

Next, I added a class method called bundle, which when called will use rubygem to generate the zip file. Note: the “permalink” attributes of Album and Artist are populated when an object of those models is created. I’m using them because it makes for nice filenames, too.

# create a zipped archive file of all the tracks in an album
def bundle(name = self.permalink, set = self.artist.permalink)
   bundle_filename = "#{RAILS_ROOT}/public/uploads/#{set}-#{name}.zip"

   # check to see if the file exists already, and if it does, delete it.
   if File.file?(bundle_filename)
     File.delete(bundle_filename)
   end

   # set the bundle_filename attribute of this object
   self.bundle_filename = "/uploads/#{set}-#{name}.zip"

   # open or create the zip file
   Zip::ZipFile.open(bundle_filename, Zip::ZipFile::CREATE) {
     |zipfile|
     # collect the album's tracks
     self.tracks.collect {
       |track|
         # add each track to the archive, names using the track's attributes
         zipfile.add( "#{set}/#{track.num}-#{track.filename}", "#{RAILS_ROOT}/public#{track.public_filename}")
       }
   }

   # set read permissions on the file
   File.chmod(0644, bundle_filename)

   # save the object
   self.save
end

Next I added a method in my controller:

def create_bundle
   album = Album.find(params[:id])
   album.bundle
   flash[:notice] = 'Album was successfully zipped.'
   redirect_to album_url(album.artist, album)
end

And edit my routes.rb accordingly:

map.create_bundle 'create_bundle/:id', :controller => 'albums', :action => 'create_bundle'

Now it’s just a matter of creating a link in the view for the admin to click whenever he/she wants to generate the zip file:

<%= link_to('Create Album Zip', create_bundle_path(@album)) %>

…and a link for the user to click to download the zip file if it exists:

<% unless @album.bundle_filename.nil? %>
<%= link_to "Download Album Zip", @album.bundle_filename %>
<% end %>

That’s it! Refer to the rubyzip documentation for more info.

Tagged as: , , No Comments
23Jun/080

make_resourceful for rails

The make_resourceful plugin is a great way to DRY up the 7 RESTful actions common in most controllers. Learn how to use it in this episode.
Tags:

plugins

Resources

script/plugin install http://svn.hamptoncatlin.com/make_resourceful/tags/make_resourceful
# products_controller.rb
make_resourceful do
actions :all

response_for :show do |format|
format.html
format.xml { render  :x ml => current_object.to_xml }
end
end

private

def current_objects
   Product.find(:all,  :o rder => 'name')
end

def current_object
   @current_object ||= Product.find_by_permalink(params[:id])
end
<!-- edit.html.erb -->
<%= hidden_field_tag '_flash[notice]', "Successfully updated product." %>
13May/080

Sort array of ActiveRecord object without querying to database.

Sometimes it may happen you want to sort the array of objects, fetched from ActiveRecord.

e.g. I have a users table having name column after I done any manipulation on the fetched object.

You can just call the following code for doing the above stuff.

@users = User.find :all
@users = @users - xyz_obj.users #remove existing users.
@users = @users.sort_by { |user| user[:name] }

May this code helps anyone....

Thanks ;-)

Tagged as: No Comments
9May/080

How to raise and rescue Exceptions in Ruby on Rails

Creating the Exception class

To create our “PersonalException” we just need to extend “Exception” class.


class PersonalException < Exception
end

Raise our Exception


raise PersonalException.new, "message"

Rescue our exception

We can do this by overwriting rescue_action_in_public and local_request? functions to our application.rb file:

18Mar/080

Ruby thumbnail generator

Ruby thumbnail generator is simple script which is ideal to use in your Ruby on Rails application to quickly generate thumbnails of any proportions. Just set width and height and get the image.

1. copy following code into /controllers/thumb_controller.rb

2. edit /config/routes.rb and add this line:
map.connect "thumb/*specs", :controller => "thumb", :action => "index"

3. create directory /imagelib/ in RoR's /public/ directory and
/image_cache/ inside /imagelib/ directoory

Now you can call /thumb/photo.jpg?w=400&h=350 and you will
see resized picture "photo.jpg". photo.jpg should be stored in
/public/imagelib/ directory. Off course you can change directory
structure if you wish just don't forget to edit thumb_controller.rb
than.

visit www.cleverleap.com/ruby-thumbnail-generator/
for more information

class ThumbController < ApplicationController

  require 'gd2'
  include GD2

  def index

    path = "imagelib/"    # default image library directory

    widthx = 500          # default width of generated image
    heightx = 500         # default height of generated image

    if params[:w] then widthx = params[:w].to_i

    end

    if params[:h] then heightx = params[:h].to_i

    end

    filepath = path + params[:specs].join("/")    # Path to file

    format = filepath.split(".").last             # Format - extension

    filename = params[:specs].last.split(".").first # just file name without extension

    #require 'digest/md5'
    digest = Digest::MD5.hexdigest( filepath )      # md5 hash

    cachefile = digest + "-" + widthx.to_s + heightx.to_s + "." + format

    picfile = filepath
    cachedpicfile = path + "image_cache/" + cachefile

    if File.exists?(cachedpicfile) && (File.stat( cachedpicfile ).mtime.to_i > File.stat( picfile ).mtime.to_i)

      picsource = cachedpicfile
      cache = true
    elsif File.exists? picfile
      picsource = picfile

    end

    if cache == true    # Read from Cache
      @pic = File.new(picsource).read

    else                # Import an image
      i = Image.import(picsource)

      if i.size[0] > i.size[1]  # Horizontal proportion. width > height.

        if i.size[0] < widthx then width = i.size[0]     # preffer smaller image width

        else width = widthx
        end

        height = width * i.size[1] / i.size[0]

      else                      # Vertical proportions
        if i.size[1] < heightx then height = i.size[1]

        else height = heightx
        end

        width = i.size[0] /(i.size[1] / height)
      end

      i.resize! width, height

      if format == "gif" then @pic = i.gif

      elsif format == "png" then @pic = i.png

      else @pic = i.jpeg 80
      end

      i.export(path + 'image_cache/' + cachefile ) # export cache file

    end

    cgi = CGI.new
  	cgi.out("type"=>"image/jpeg") { @pic }

  	render :nothing => true

  end
end
Tagged as: , No Comments
18Mar/080

god Server process monitoring and notifying tool written in ruby

Progress on god is moving along as quick as ever. Most interestingly you'll find several useful new command line functions:

  • god status prints out the status of each Watch
  • god log shows realtime logs for a specific Watch (even if you don't have god logging to file)
  • god load loads or reloads a config file into a running god instance
  • god terminate stops all Watches and then stops god (useful when testing your setup)

The logging system has been beefed up with proper timestamps and criticality levels. Log messages are more complete overall. You can also get the STDOUT/STDERR of a god-daemonized process written to a log file by specify 'w.log = ' in your Watch config.

If you let god daemonize your process for you, there's no need to provide a stop command. A default killing lambda will take care of gracefully (or not so gracefully if necessary) stopping your god-daemonized process.

The validity of your config file is checked better than previous versions to point you to the problem area of your config.

The bug that prevented group control from working has been fixed so you can now start/stop/etc groups of Watches.

Updated documentation is now available on the website:

http://god.rubyforge.org/

WHAT IS GOD?

God is an easy to configure, easy to extend monitoring framework written in Ruby.

Keeping your server processes and tasks running should be a simple part of your deployment process. God aims to be the simplest, most powerful monitoring application available.

INSTALL

sudo gem install god

FEATURES

  • Config file is written in Ruby
  • Easily write your own custom conditions in Ruby
  • Supports both poll and event based conditions
  • Different poll conditions can have different intervals
  • Easily control non-daemonized processes

EXAMPLE

The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is to keep the mongrels running:

# file:      application_name.god
# run with:  god -c /path/to/application_name.god
# 
# This is the actual config file used to keep the mongrels of
# application.com running.
RAILS_ROOT = "/var/www/application_name/current"
%w{8001 8002 8003}.each do |port|
  God.watch do |w|
    w.name = "application_name-mongrel-#{port}"
    w.interval = 30.seconds # default
    w.start = "mongrel_rails cluster::start --only #{port} \
      -C #{RAILS_ROOT}/config/mongrel_cluster.yml"
    w.stop = "mongrel_rails cluster::stop --only #{port} \
      -C #{RAILS_ROOT}/config/mongrel_cluster.yml"
    w.grace = 10.seconds
    w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")    
    w.behavior(:clean_pid_file)
    w.start_if do |start|
      start.condition(:process_running) do |c|
        c.interval = 5.seconds
        c.running = false
      end
    end 
    w.restart_if do |restart|
      restart.condition(:memory_usage) do |c|
        c.above = 150.megabytes
        c.times = [3, 5] # 3 out of 5 intervals
      end    
      restart.condition(:cpu_usage) do |c|
        c.above = 50.percent
        c.times = 5
      end
    end
  end
end

Configuration for nginx and mysql
I found a gr8 post for sample configuration here

DOCS

Detailed documentation is available at http://god.rubyforge.org/

Original Source...