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.)

22Jul/091

Step-By-Step setup slicehost server (fedora) for rails application.

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
26Feb/090

Keep either file in merge conflicts with git

So, the scenario is: you’re in the middle of a merge, and you want to keep one file or the other.

$ git merge master
Auto-merged _layouts/default.html
CONFLICT (content): Merge conflict in _layouts/default.html
Auto-merged index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

There’s two unmerged files here. According to the git checkout manpage, there’s a --theirs and --ours options on the command. The former will keep the version of the file that you merged in, and the other will keep the original one we had.

The following commands will keep the original file for index.html, and then use the merged in file only for _layouts/default.html.

git checkout --ours index.html
git checkout --theirs _layouts/default.html

Sadly, these options are only in Git versions 1.6.1 and up. If you have an older version and don’t feel like upgrading, there’s ways to get around this. To emulate --theirs, we’d do:

git reset -- _layouts/default.html
git checkout MERGE_HEAD -- _layouts/default.html

And for --ours:

git reset -- index.html
git checkout ORIG_HEAD -- index.html

Of course, once you’ve got the conflicts worked out, git add whatever changes need to be added in, and git commit away. If you’ve run into other problems with merging that could possibly help out others, comment away!



referred from http://gitready.com/advanced/2009/02/25/keep-either-file-in-merge-conflicts.html

Tagged as: , , , No Comments
19Feb/090

Setting up a new remote git repository

For the impatient

Set up the new bare repo on the server:

$ ssh myserver.com
Welcome to myserver.com!
$ mkdir /var/git/myapp.git && cd /var/git/myapp.git
$ git --bare init
Initialized empty Git repository in /var/git/myapp.git
$ exit
Bye!

Add the remote repository and push:

$ cd ~/Sites/myapp
$ git remote add origin ssh://myserver.com/var/git/myapp.git
$ git push origin master

Set the local master branch to track the remote branch.

Read further for a step-by-step explanation of what’s going on.

Pre-flight sanity check

Setting up a remote repository is fairly simple but somewhat confusing at first. Firstly, let’s check out what remote repositories are being tracked in our git repo:

$ cd ~/Sites/myapp
$ git remote

None. Looking good. Now let’s list all the branches:

$ git branch -a
* master

Just one branch, the master branch. Let’s have a look at .git/config:

$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true

A pretty bare-minimum config file.

Creating the bare remote repository

Before we can push our local master branch to a remote repository we need to create the remote repository. To do this we’ll ssh in and create it on the server:

$ ssh myserver.com
Welcome to myserver.com!
$ cd /var/git
$ mkdir myapp.git
$ cd myapp.git
$ git --bare init
Initialized empty Git repository in /var/git/myapp.git
$ exit
Bye!

A short aside about what git means by bare: A default git repository assumes that you’ll be using it as your working directory, so git stores the actual bare repository files in a .git directory alongside all the project files. Remote repositories don’t need copies of the files on the filesystem unlike working copies, all they need are the deltas and binary what-nots of the repository itself. This is what “bare” means to git. Just the repository itself.

Adding the remote repository to our local git repository configuration

Now that we’ve created the remote repository we’ll add it to our local repository as a remote server called “origin” using git remote add, which is just a nicer way of updating our config file for us:

$ git remote add origin ssh://myserver.com/var/git/myapp.git

Let’s see what it added to the config file:

[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
  logallrefupdates = true
[remote "origin"]
  url = ssh://myserver.com/var/git/myapp.git
  fetch = +refs/heads/*:refs/remotes/origin/*

We now have a remote repository “origin” that will fetch all of it’s refs/heads/* branches and store them in our local repo in refs/remotes/origin/* when a git fetch is performed.

Pushing to the remote repository

The time has come to push our local master branch to the origin’s master branch. We do that using the git push command.

$ git push origin master
updating 'refs/heads/master'
  from 0000000000000000000000000000000000000000
  to   b379203bc187c2926f44a71eca3f901321ea42c6
 Also local refs/remotes/origin/master
Generating pack...
Done counting 1374 objects.
Deltifying 1374 objects...
 100% (1374/1374) done
Writing 1374 objects...
 100% (1374/1374) done
Total 1374 (delta 89), reused 0 (delta 0)
refs/heads/master: 0000000000000000000000000000000000000000 -> b379203bc187c2926f44a71eca3f901321ea42c6

and that’s all, folks. Further pushes can be done by repeating the git push command.

Now you can tell your co-conspirators to:

$ git clone ssh://myserver.com/var/git/myapp.git

and push and pull to your heart’s content.

Track the remote branch

You can specify the default remote repository for pushing and pulling using git-branch’s track option. You’d normally do this by specifying the --track option when creating your local master branch, but as it already exists we’ll just update the config manually like so:

[branch "master"]
  remote = origin
  merge = refs/heads/master

Now you can simply git push and git pull.

Sharing the remote repository with the world

If you want to set it up as a public repository be sure to check out the Git manual’s chapter on public git repositories.

Working with remote repository branches

git remote show is used to inspect a remote repository. It goes and checks the remote repository to see what branches have been added and removed since the last git fetch.

Doing a git remote show at the moment only shows us the remote repo’s master branch which we pushed earlier:

$ git remote show origin
* remote origin
  URL: ssh://myserver.com/var/git/myapp.git
  Tracked remote branches
    master

Let’s create a new local git repository and push to a new branch on the remote repository. We can then use git remote show to see the new remote branch, git fetch to mirror it into our local repo and git checkout --track -b to create a local branch to do some work on it.

We’ll start by creating a new local repo and pushing some code to a new branch in the remote repository.

$ mkdir /tmp/other-git
$ cd /tmp/other-git
$ git init
Initialized empty Git repository in /tmp/other-git
$ git remote add origin ssh://myserver.com/var/git/myapp.git
$ echo "Rails 2... woo" > afile
$ git add afile
$ git commit -m "Added afile" 
Created initial commit 0ac9a74: Added afile
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 something
$ git push origin master:refs/heads/dev/rails-2
updating 'refs/heads/rails-2' using 'refs/heads/master'
  from 0000000000000000000000000000000000000000
  to   0ac9a7457f4b21c9e058d4c54d262584bf35e528
 Also local refs/remotes/origin/rails-2
Generating pack...
Done counting 3 objects.
Deltifying 3 objects...
 100% (3/3) done
Writing 3 objects...
 100% (3/3) done
Total 3 (delta 0), reused 0 (delta 0)
Unpacking 3 objects...
 100% (3/3) done
refs/heads/rails-2: 0000000000000000000000000000000000000000 -> 0ac9a7457f4b21c9e058d4c54d262584bf35e528

Now let’s switch back to our old git repository and see if it detects the new branch on the remote repository:

$ git remote show origin
* remote origin
  URL: ssh://myserver.com/var/git/myapp.git
  New remote branches (next fetch will store in remotes/origin)
    dev/rails-2
  Tracked remote branches
    master

Let’s update our mirror of the remote repository by doing a git fetch:

$ git fetch
* refs/remotes/origin/master: storing branch 'dev/rails-2' of ssh://myserver.com/var/git/myapp.git
  commit: b379203
$ git remote show origin
* remote origin
  URL: ssh://myserver.com/var/git/myapp.git
  Tracked remote branches
    master
    dev/rails-2

We should now be able to see this in a our list of remote branches:

$ git branch -a
* master
origin/dev/rails-2
origin/master

If we then wanted to do some work on this remote dev/rails-2 branch we create a new local tracking branch like so:

$ git checkout --track -b dev/rails-2 origin/dev/rails-2
Branch dev/rails-2 set up to track remote branch refs/remotes/origin/dev/rails-2.
Switched to a new branch "dev/rails-2"

To keep up-to-date and push new changesets we simply use git push and git pull when working in the local dev/rails-2 branch.

Also notice, like we manually changed for master, .git/config has a new entry for this new tracking branch:

[branch "dev/rails-2"]
  remote = origin
  merge = refs/heads/dev/rails-2
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." %>
17May/080

Audit site using acts_as_audited plugin

acts_as_audited is an Active Record plugin that logs all modifications to your models in an audits table. It uses a polymorphic association to store an audit record for any of the model objects that you wish to have audited. The audit log stores the model that the change was on, the “action” (create, update, destroy), a serialzied hash of the changes, and optionally the user that performed the action.

Auditing in Rails

NOTE: read the caveats section if the following isn’t working.

If you’re using acts_as_audited within Rails, you can simply declare which models should be audited. acts_as_audited can also automatically record the user that made the change if your controller has a current_user method.

class ApplicationController < ActionController::Base

audit User, List, Item
protected
def current_user
@user ||= User.find(session[:user])

end
end

Caveats

Auditing with user support depends on Rails’ caching mechanisms, therefore auditing isn’t enabled during development mode. To test that auditing is working, start up your app in production mode, or change the following options in config/environments/development.rb:

config.cache_classes = true

config.action_controller.perform_caching = true

Customizing

To get auditing outside of Rails, or to customize which fields are audited within Rails, you can explicitly declare acts_as_audited on your models. The :except option allows you to specify one or more attributes that you don’t want to be saved in the audit log.

class User < ActiveRecord::Base
acts_as_audited :except => [:password, :credit_card_number]

end

Installation

You can grab the plugin by running:

script/plugin install http://source.collectiveidea.com/public/rails/plugins/acts_as_audited

Run the migration generator and migrate to add the audits table.

script/generate audited_migration add_audits_table
rake db:migrate

Upgrading

Those upgrading from version 0.2 need to add 2 fields the audits table:

add_column :audits, :user_type, :string
add_column :audits, :username, :string

May this information fulfills your requirement... ;-)