« November 2008 | Main | January 2009 »

December 2008 Archives

December 7, 2008

Subversion Primer

There comes a time when version control becomes a necessity; that's when Subversion comes to the rescue. Having worked with both CVS and Subversion, I recommend avoiding the baroque intricacies of CVS for the simplicity of Subversion. This is specially true if you have a project with an evolving source tree. Follow the links above for an introduction to Subversion.

There are a few things to note however, when attempting to use Xcode 3.1 with Subversion 1.5.x. It seems that Xcode is hardwired to verify the repository version. A repository created with the 1.4 version of the svnadmin returns a version identifier of 2, whereas the 1.5 of the command creates a version 3 repository. This may have to do with the back end databases used by the repository. Without significant hacking, it seems like a lot of work with marginal benefit. For now, I'd recommend using the packaged 1.4.4 that comes with OS X 10.5.5.

One last thing: it seems that launchctl will be the default method for managing startup daemons going forward in OS X. This means that the older SystemStarter service will be deprecated in the near future. There is an article at The Wishing Line which discussed a method for automating svnserve startups using launchctl. Be sure to modify the .plist to use the correct paths for your binaries and repository. As with PostgreSQL, I created symbol links from /usr/local to the actual repository to keep a clean separation between the system defaults versus any customizations that I introduce into my computing environment through 3rd party applications.

With OS X 10.5.5, I found that the 1.4.4 version of svnserve included with the developer tools was located in the /usr/bin directory. You can verify this on your system with the following command:

# which svnserve

Take note of the path returned by this command; it is necessary for the .plist file.

One last customization to the .plist file was changing the default --daemon command argument and replacing it with the --tunnel argument to support svn+ssh. If you plan to use this feature for a network accessible Subversion server, keep in mind that you will also have to enable the Remote Login privilege to be enabled on your machine under System Preferences -> Sharing.

For the sake of completeness, here is my modified .plist file:





	Label
	org.tigris.Subversion
	ProgramArguments
	
		/usr/bin/svnserve
		--tunnel
		--root
		/usr/local/svn
	
	RunAtLoad
	
	ServiceDescription
	Subversion Server
	StandardErrorPath
	/dev/null
	UserName
	root


As with all these articles, please feel free to comment if you find and error or wish to add something that I've overlooked.

December 8, 2008

RailRoad

Here are some notes I've collected as I've worked through developing my application on Rails:

PostgreSQL

I generally prefer using PostgreSQL for my personal projects. PostgreSQL's pedigree and consistent level of technical superiority means that I'll never have to second guess my decision regarding the database as an application's use begins to scale. Given Monty Widenius' rant against MySQL 5.1, I don't foresee it approaching the capabilities of PostgreSQL anytime soon.

Rails Database Adapters

That being said, there were a few caveats to keep in mind for Rails to use PostgreSQL as a back end store. The first is clarification on which gem adapter module is required for rails configuration. There are two - one which is a pure ruby driver, the other a compiled native driver. The postgres-pr (the pure ruby PostgreSQL driver) worked right out of the box. The pros of this driver is it is implemented in ruby; the con however, is that it is relatively slow compared to the native driver.

With the latest version of rails (2.2.2), I found that the postgresql gem is no longer recognized. It has been superceded by the postgres native adapter. Attempting to compile the postgres gem against my Fink managed PostgreSQL 8.3 installation resulted in the following errors:

Building native extensions.  This could take a while...
ERROR:  Error installing postgres:
	ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb install postgres

===========   WARNING   ===========

You are building this extension on OS X without setting the
ARCHFLAGS environment variable, and PostgreSQL does not appear
to have been built as a universal binary. If you are seeing this
message, that means that the build will probably fail.

Try setting the environment variable ARCHFLAGS
to '-arch i386' before building.

For example:
(in bash) $ export ARCHFLAGS='-arch i386'
(in tcsh) $ setenv ARCHFLAGS '-arch i386'

Then try building again.

===================================
checking for main() in -lpq... yes
checking for libpq-fe.h... yes
checking for libpq/libpq-fs.h... yes
checking for PQsetClientEncoding()... no
checking for pg_encoding_to_char()... no
checking for PQfreemem()... no
checking for PQserverVersion()... no
checking for PQescapeString()... no
creating Makefile

make
gcc -I. -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0 -I. -DHAVE_LIBPQ_FE_H -DHAVE_LIBPQ_LIBPQ_FS_H -I/sw/include/postgresql  -fno-common -arch ppc -arch i386 -Os -pipe -fno-common  -c libpq-compat.c
libpq-compat.c: In function 'PQescapeBytea':
libpq-compat.c:104: warning: incompatible implicit declaration of built-in function 'sprintf'
libpq-compat.c:104: warning: pointer targets in passing argument 1 of 'sprintf' differ in signedness
libpq-compat.c: In function 'PQunescapeBytea':
libpq-compat.c:158: warning: incompatible implicit declaration of built-in function 'strlen'
libpq-compat.c:158: warning: pointer targets in passing argument 1 of 'strlen' differ in signedness
libpq-compat.c: In function 'PQescapeBytea':
libpq-compat.c:104: warning: incompatible implicit declaration of built-in function 'sprintf'
libpq-compat.c:104: warning: pointer targets in passing argument 1 of 'sprintf' differ in signedness
libpq-compat.c: In function 'PQunescapeBytea':
libpq-compat.c:158: warning: incompatible implicit declaration of built-in function 'strlen'
libpq-compat.c:158: warning: pointer targets in passing argument 1 of 'strlen' differ in signedness
gcc -I. -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0 -I. -DHAVE_LIBPQ_FE_H -DHAVE_LIBPQ_LIBPQ_FS_H -I/sw/include/postgresql  -fno-common -arch ppc -arch i386 -Os -pipe -fno-common  -c postgres.c
postgres.c:41: error: static declaration of 'PQserverVersion' follows non-static declaration
/sw/include/postgresql/libpq-fe.h:262: error: previous declaration of 'PQserverVersion' was here
postgres.c:41: error: static declaration of 'PQserverVersion' follows non-static declaration
/sw/include/postgresql/libpq-fe.h:262: error: previous declaration of 'PQserverVersion' was here
postgres.c: In function 'Init_postgres':
postgres.c:2676: error: 'pgconn_protocol_version' undeclared (first use in this function)
postgres.c:2676: error: (Each undeclared identifier is reported only once
postgres.c:2676: error: for each function it appears in.)
postgres.c:2677: error: 'pgconn_server_version' undeclared (first use in this function)
postgres.c: In function 'Init_postgres':
postgres.c:2676: error: 'pgconn_protocol_version' undeclared (first use in this function)
postgres.c:2676: error: (Each undeclared identifier is reported only once
postgres.c:2676: error: for each function it appears in.)
postgres.c:2677: error: 'pgconn_server_version' undeclared (first use in this function)
lipo: can't open input file: /var/tmp//ccZF2c6t.out (No such file or directory)
make: *** [postgres.o] Error 1

The error appeared despite setting the ARCHFLAGS environment variable and supplying the POSTGRES_INCLUDE argument to the gem install command. I finally got it to compile correctly after a bit of digging:

# sudo env ARCHFLAGS="-arch i386" gem install postgres

Note how the ARCHFLAGS needed to be passed into sudo. Good to know someone out there already figured it out.

To use either of these database adapters, you will need to ensure that the config/database.yml file specifies postgresql for the adapter parameter. The default is sqlite3. It's probably a good idea to have only either the ruby or native driver installed at any given time.

In addition, you should remove the database parameter from the database.yml file. These are only required for SQLite databases.

PostgreSQL Application Accounts

The last bit of configuration requires each of the different releases (development, test, and production) have their own database users. It is generally good practice to completely keep these environments isolated from one another to avoid accidental loss of data. The config/database.yml file requires additional information to configure these separate connections. Each entry in the database.yml should have the following parameters:

host : machine_name
username : database_user
password : database_password

Due to the sensitive nature of the information contained in the database.yml file, it is highly recommended that this file be NOT world readable.

All of this configuration is fruitless without actual PostgreSQL users. Use the following commands to create a database and user for each of these environments (these commands assume that you are the local PostgreSQL user):

# createuser -SdRlEP development
# createuser -SdRlEP test
# createuser -SdRlEP production

The options will result in PostgreSQL users which will not have superuser privileges or the ability to create new roles, but have privileges to create databases (for scaffold creation/teardown) and log in. As well, the account will have an encrypted password.

Once these accounts have been created, you will need databases to associate with each of them:

# createdb -E UTF8 -O development dev_database_name
# createdb -E UTF8 -O test test_database_name
# createdb -E UTF8 -O production prod_database_name

The last step requires enabling psql local machine connections so that you can inspect the structure of the database for each of these releases are the evolve over the development process. This requires modifying the data/pg_hba.conf file for PostgreSQL. There should be entries for each user and database for each local address group (localhost / local IPV4 / local IP6).

# "local" is for Unix domain socket connections only
local        dev_database_name              development	md5
local 	test_database_name            	test   		md5
local 	prod_database_name        	production	md5

# IPv4 local connections:
host 	dev_database_name	development	127.0.0.1/32	md5
host 	test_database_name	test   		127.0.0.1/32	md5
host 	prod_database_name	production	127.0.0.1/32	md5

# IPv6 local connections:
host 	dev_database_name	development	::1/128		md5
host 	test_database_name	test	        	::1/128		md5
host 	prod_database_name	production	::1/128		md5

By specifying the encrypt password option when creating the database roles, you ensure that passwords are never transmitted in clear text. As a consequence, you must use the MD5 authentication method in the pg_hba.conf file.

As with any configuration changes, you will have to restart the server for the changes to be applied. Test the accounts by making local psql connections by specifying both the user and database as options:

# psql -U development -d dev_database_name

If you plan on making the PostgreSQL account accessible over the network it is highly recommended that you secure your connections using SSL. Please refer to the PostgreSQL documentation to configure the server with OpenSSL certificates.

Here are some useful PostgreSQL/Ruby links:

Rails

Gem Management

Here are some useful commands for rails:

Get the a remote list of gems available.

# gem list --remote

Find a gem either in the local or remote repository.

# gem search --both name_of_gem

Display a remote gem's specifications.

# gem specification --remote name_of_gem

Search for remote generator gems which can be installed.

# gem search -r generator

Here are a list of useful gems:

  • ruby-debug

Rails Scaffolding

Rails excels as a tool for rapid prototyping with a focus on web applications which adhere to the Model-View-Controller (MVC) design paradigm. Using a relatively succinct number of ruby scripts, project scaffolding can be generated quickly and efficiently. Before projects can be automatically run in Xcode, the project must first be configured for use. This requires the following steps:

  1. Generate the basic project framework using the following command:

    # rails project_name
    

    This will generate a core project scaffold which contains all the required files and default configuration for a basic rails application.

  2. Open Xcode and drag the generated application directory into the Project & Sources category in the Organizer window.
  3. Click the Run icon and select Edit Actions ...
  4. Create a new item named.
    • Create a new item named start server.
    • In the Directory drop down, select the Top Level Organizer Item option.
    • In the Command text box, enter the following command : script/server. This corresponds to a ruby script located in the script directory generated by the initial rails scaffolding command.
    • Ensure that there are no Arguments.
    • Click OK to save the Run Action.
  5. At this point, clicking the Run icon should start the ruby application on your local machine. Pointing a browser to the http://localhost:3000 address should display the default web page for the application.

By default, Rails uses the Active Record pattern to persist application objects to a relational database.

To generate scaffolding for application objects which create default entries for each of the MVC components issue the following command from the top of the application directory:

# ./script/generate scaffold object_name property:data_type property:data_type

where:

  • the object_name is the class of application object you wish to create scaffolding for.
  • the property is a property or attribute of the application object.
  • the data_type is the storage data type of property.

In addition to the MVC files, the scaffold generate script also creates a migration file which allows database schema to upgraded/downgraded as the application is developed. In addition, by specifying different development, test, and production databases in the configuration, these separate environments remain isolated.

Caveats

2.2.2 Release Notes

There are number of significant changes introduced to Rails 2.2.2. These result in older applications being unable to run in the new Rails environment. It is highly recommended that you read the Release Notes for 2.2.2 to be sure that your application is not broken by this upgrade. The following is a list of a number of issues that I encountered.


The following command is deprecated in Rails 2.2.2 in config/environments/development.rb:

config.action_view.cache_template_extensions = false

Using Inflectors requires a change to the default inflections.rb in Rails 2.2.2 :

 ActiveSupport::Inflector.inflections do |inflect|
   inflect.plural /^(ox)$/i, '\1en'
   inflect.singular /^(ox)en/i, '\1'
 end

Failing to add the ActiveSupport namespace qualifier will result in the following initialization error :

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:445:in `load_missing_constant': uninitialized constant Inflector (NameError)
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:77:in `const_missing'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:89:in `const_missing'
	from /Users/mel/Documents/Workspace/vuespace/src/config/initializers/inflections.rb:5
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in `load_without_new_constant_marking'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in `load'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:521:in `new_constants_in'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in `load'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/initializer.rb:550:in `load_application_initializers'
	 ... 32 levels...
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/commands/server.rb:49
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
	from /Users/mel/Documents/Workspace/vuespace/src/script/server:3

Rails now supports database connection pooling to support larger numbers of concurrent users. This feature is enabled by default in the supplied database.yml file where the pool parameter (which specifies the maximum number of connections to use) is specified with a default. In addition, configuration now also supports the wait_timeout (the amount of time to wait before trying another connection; the default is 5 seconds) parameter.

About December 2008

This page contains all entries posted to Z1R0 in December 2008. They are listed from oldest to newest.

November 2008 is the previous archive.

January 2009 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Creative Commons License
This weblog is licensed under a Creative Commons License.