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:
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.
- Open Xcode and drag the generated application directory into the Project & Sources category in the Organizer window.
- Click the Run icon and select Edit Actions ...
- 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 thescriptdirectory generated by the initialrailsscaffolding command. - Ensure that there are no Arguments.
- Click OK to save the Run Action.
- At this point, clicking the Run icon should start the ruby application on your local machine. Pointing a browser to the
http://localhost:3000address 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 NotesThere 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.



