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.

Wednesday, December 13, 2006

Uninstalling MySql on OSX

Recently I installed mysql-5 on my laptop using the .dmg installer. Later I decided that I wanted to use mysql-4 instead. Since there is no mysql uninstaller for os x, I did [rm -rf /usr/local/mysql], thinking this would do the trick. The problem, however, is now when I try to install mysql I keep getting the message "You cannot continue. There is nothing to install." After poking around a bit more I found out that you need to delete the "mysql*.pkg/" directories located in /Library/Receipts

That did the trick!

Friday, December 08, 2006

Finally Got Mysql/Postgres Gem to Install

The incantation:

gem install mysql -- --with-mysql-lib=/opt/csw/lib/mysql --with-mysql-include=/opt/csw/mysql5/include/mysql

gem install postgres -- --with-pgsql-lib=/opt/csw/postgresql/lib --with-pgsql-include=/opt/csw/postgresql/include

The reason this was tricky, is because our sysadmin guys didn't install the mysql-devel libraries. They did however install the mysql4rt (runtime) stuff. I ended up installing the devel libraries in my home directory while the sysadmin guys get around to it.

Somewhat related, is how I improperly used ruby's [mkmf] library to debug the gem installation. Each gem that needs to build C extensions, uses an extconf.rb file that runs a bunch of crap and ends up generating a Makefile. The extconf.rb file makes heavy use of ruby's [mkmf] library. Anyway, I noticed that the extconf.rb script kept bombing out during its call to: [find_library('mysqlclient', 'mysql_query', lib] where [lib = /path/to/static/lib/mysql]. This seemed odd since the [lib] var was pointing to the mysql static libraries that I installed in my home directory. So I tried using irb to isolate the problem:

irb(main):001:0> require 'mkmf'
=> true
irb(main):002:0> lib = "/path/to/static/lib/mysql"
=> "/path/to/static/lib/mysql"
irb(main):003:0> find_library('mysqlclient', 'mysql_query', lib)
=> false

WTF?

For some reason I thought that the find_library() function wanted to know the path to the static library 'libmysqlclient.a'. This is not the case, it actually wants the path to the location of the shared library 'libmysqlclient.so'. Once I figured this out, I was able build the extension and find_library() was able to find the library:

irb(main):001:0> require 'mkmf'
=> true
irb(main):006:0> lib = '/path/to/shared/lib/mysql
=> "/path/to/shared/lib/mysql"
irb(main):007:0> find_library('mysqlclient', 'mysql_query', lib)
checking for mysql_query() in -lmysqlclient... yes
=> true

Tuesday, December 05, 2006

The True Meaning of libx.a Files

I don't really know C very well, so I was surpirsed (and delighted) when I finally learned what all those libx.a files are. For example, if you have mysql installed on your system, go take a look in the mysql/lib directory. You should see a bunch of files ending in .a . These are archive files containing compiled C code, basically they are the same thing as a java .jar file. Who knew?

If you want to check the contents of the arhive you can use the [nm] command. Like [nm libmysqlclient.a]

Want to know if the arhive has a specific function? [nm libmysqlclient.a | grep mysql_query]