Thursday, December 27, 2007

Connecting to Remote DB with psql

psql -h host.crap.com -U user_name -d database_name

For more options, see the postgres manual: http://www.postgresql.org/docs/8.1/interactive/app-psql.html

Wednesday, August 22, 2007

Example of Using svn:externals

svn propset svn:externals "ucb_tasks $svn_commons/ucb-rails-application-scaffold/trunk/lib/tasks" ucb_rails_logs/lib/tasks

Thursday, May 24, 2007

Ruby / Rails and Web Services

Making web services in Rails is pretty easy. Recently I created a test web service following the instructions located here: http://manuals.rubyonrails.com/read/chapter/67

For this example, I'm going to create two web services. One will interface with a Color API and the other with a Person API. For the Color API, we need to create a color model, extending ActiveRecord::Base. The color model should have 1 attribute (db column): "name". Now create a person model, extending ActiveRecord::Base, and give it the following attributes: first_name, last_name, email. As always, these classes go in the models dir of your Rails app.


Here are the migrations for populating your tables:


class AddColorsTable < ActiveRecord::Migration
def self.up
create_table :colors do |t|
t.column :name, :string
end
end

def self.down
drop_table :colors
end
end

class AddPersonTable < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.column :uid, :string
t.column :first_name, :string
t.column :last_name, :string
t.column :email, :string
end
end

def self.down
drop_table :people
end
end


Next, use script/generate to fire off the creation of the web service:

rooster> script/generate web_service remote


This creates an "apis" directory beneath the "app" directory and adds one file to it: "remote_api.rb." It also adds a "remote_controller.rb" to the controller directory. We're going to use delegated dispatching so we don't need the remote_api.rb class, deleted it, I did :-). If you care, you can read all about the different dispatching types at the above URL.

Now add the following to your remote_controller.rb file:


class RemoteController < ApplicationController
web_service_dispatching_mode :delegated
web_service_scaffold :invoke

web_service :person, PersonService.new
web_service :color, ColorsService.new
end


Brief explanation of the class:
web_service_dispatching_mode: specifies dispatch type
web_service_scaffold: this allows us to test our web server by going to: localhost:3000/remote/invoke
web_service: name, instantiate (this declares one of our web services).


Ok, let's create the PersonService. Add the below classes to the "apis" directory.


person_service.rb:
class PersonService < ActionWebService::Base
web_service_api PersonApi

def find_all
Person.find(:all)
end

def find_by_name(last_name, first_name)
hash = {:first_name => first_name, :last_name => last_name}
hash.reject! {|key, val| val.blank?}
query_string = hash.map {|key, val| "#{key} = '#{val}'"}.join(" and ")

return [] if query_string.blank?
Person.find(:all, :conditions => query_string)
end
end

person_api.rb
class PersonApi < ActionWebService::API::Base
api_method :find_all,
:returns => [[Person]]

api_method :find_by_name,
:expects => [{:last_name => :string}, {:first_name => :string}],
:returns => [[Person]]
end


Now the ColorsService:


colors_service.rb
class ColorsService < ActionWebService::Base
web_service_api ColorsApi

def find_all_colors
Color.find(:all).map {|c| c.name}
end

def find_color_by_name(name)
c = Color.find_by_name(name)
c.name unless c.nil?
end
end

colors_api.rb
class ColorsApi < ActionWebService::API::Base

api_method :find_all_colors,
:returns => [[:string]]

api_method :find_color_by_name,
:expects => [{:color_name => :string}],
:returns => [:string]
end


You can view the WSDL for these services by going to: http://localhost:3000/remote/service.wsdl. Note, the wsdl contains info for both services.


Ok, so now let's test our service. Fire up irb so we can play a nice game of Simon Says.


rooster@banway28 > irb
irb(main):001:0> require 'soap/wsdlDriver'
=> true

irb(main):002:0> driver = SOAP::WSDLDriverFactory.new("http://localhost:3000/remote/service.wsdl")

=> #
irb(main):003:0> person_rpc = driver.create_rpc_driver("Service", "PersonPort")

=> #>
irb(main):005:0> color_rpc = driver.create_rpc_driver("Service", "ColorPort")

=> #>
irb(main):006:0> color_rpc.findAllColors

=> ["red", "green", "blue", "yellow", "orange", "black", "white"]
irb(main):007:0> person_rpc.findAll
=> [#, #, #, #]

irb(main):008:0> person_rpc.findByName("", "steven")
=> []

irb(main):009:0> person_rpc.findByName("", "steve")
=> [#, #]

irb(main):010:0> person_rpc.findByName("", "steve").first.first_name
=> "Steve"


Pretty neat stuff eh? The key thing to keep in mind, is that with delegated dispatching, you need to create separate rpc drivers for each API you want to interact with. That's why I created the person_rpc and colors_rpc objects.


Next time I'll show you how to update/create data using SOAP and ruby.

Monday, May 21, 2007

Installing Rubygems in a Non-Standard Dir

From the rubygems FAQ: http://rubygems.org/read/chapter/15

You have to redefine the location of the GEM_HOME variable and add the paths to the gem repositories in the RUBYLIB variable before launching the installation into a custom directory.

GEM_HOME should point to $PREFIX/lib/ruby/gems/1.8 if it used with the 1.8 version of ruby.

RUBYLIB should point to the $PREFIX/lib/ruby and $PREFIX/lib/site_ruby/1.8

Here is a shell script that runs in the rubygems distribution directory to install into /home/user :

PREFIX=$HOME
export GEM_HOME=$PREFIX/lib/ruby/gems/1.8
export RUBYLIB=$PREFIX/lib/ruby:$PREFIX/lib/site_ruby/1.8
ruby setup.rb all --prefix=$PREFIX

You may add GEM_HOME and RUBYLIB into your ~/.profile file to automatically load on login.