Archive for May, 2008

Akelos is some new hotness for PHP

Thursday, May 22nd, 2008

Ok, so I don’t usually blog about PHP….well in this blog you’ll see zero previous posts about PHP….but I’ve been keeping tabs on a new PHP MVC framework called Akelos. What is intriguing to me about Akelos is it’s a direct port of the Rails framework for PHP.

Now, for an avid Rails developer having to code a project in PHP this is the best solution. We have to admit, at times we’re not “allowed” to code a project in Rails. Whether it be a legacy PHP system or a rigid decision by a new client, some times we’re in a situation where we HAVE to code in PHP. Enter Akelos.

So the first thing that caught my attention as a “wow” factor of Akelos over CakePHP, Symfony or one of the other PHP MVC frameworks(besides being a port of Rails) was the use of sintags. This is an especially nice feature for Rails developers using Akelos. 

Sintags allows you to use Ruby syntax in a number of Akelos views including such calls as “render :partial => “your partial name”. This is a fantastic bridge between the two frameworks for someone in my situation. 

Hop on Akelos.org and checkout some of the features and Rails similarities for yourself.

I’ll post some code comparisons of sintags in a future post. 

 

Easier Capistrano Deployment with legacy databases.

Saturday, May 17th, 2008

As my last Rails project was drawing to a close and deployment tasks were closing in, it became apparent I’d have my work cut out for me when deploying each box. This project was in no way adhering to “the Rails way” with regards to database architecture(or anything else for that matter…..a topic for another post).

With this odd system setup I had to get creative with the Capistrano deployment file. I’ve include my solution to the legacy db problem. As you will see, I’ve added “before” and “after” method calls to handle the proper linking of the project and it’s database.yml after building it from within my deploy.rb file.

So what happens now?

Now when you run cap:deploy from your app root the :db namespace will be run prior to the usual setup. This will build the database.yml file from the entry examples below and process the symlink updates after the script has completed.

Voila! A nice, easy way to manage connections to multiple databases through capistrano.

require 'erb'

#require 'mongrel_cluster/recipes'

before “deploy:setup”, :db

after “deploy:update_code”, “db:symlink”

set :user, “–yourusername–”

set :used_sudo, “true”

set :svn_user, ENV[’svn_user’] || “yoursvnusername”

set :svn_password, Proc.new { Capistrano::CLI.password_prompt(’SVN Password: ‘) }

set :repository,

Proc.new { “–username #{svn_user} ” +

“–password #{svn_password} ” +

“–no-auth-cache ” +

“http://–yoursvnurl–/”}

set :spinner, “false”

set :application, “–yourappname–”

set :deploy_to, “/var/www/#{application}”

set :mongrel_conf, “#{deploy_to}/current/config/mongrel_cluster.yml”

role :app, “yourip”

role :web, “yourip”

# role :app, “yourip”

# role :web, “yourip”

# role :db, “yourip”, :primary => true

role :db, “yourip”, :primary => true

namespace :db do

desc “Create database.yml in shared/config”

task :default do

database_configuration = ERB.new <<-EOF

development:

adapter: sqlserver

mode: odbc

dsn: dsn1

username:

password:

test:

adapter: sqlserver

mode: odbc

dsn: dsn1

username:

password:

production:

adapter: sqlserver

mode: odbc

dsn: dsn1

username:

password:

legacy_db1:

adapter: sqlserver

mode: odbc

dsn: dsn2

username:

password:

legacy_db2:

adapter: sqlserver

mode: odbc

dsn: dsn3

username:

password:

legacy_db3:

adapter: sqlserver

mode: odbc

dsn: dsn4

username:

password:

EOF

run “mkdir -p #{deploy_to}/#{shared_dir}/config”

put database_configuration.result, “#{deploy_to}/#{shared_dir}/config/database.yml”

end

desc “Link in the production database.yml”

task :symlink do

run “ln -nfs #{deploy_to}/#{shared_dir}/config/database.yml #{release_path}/config/database.yml”

end

end


Adapter specific date handling in Rails

Thursday, May 15th, 2008

Lately I’ve had to endure working on a Rails project where the requirements dictate the use of Microsoft SQL Server as the choice database. In addition, we’ve had to test environments consisting of Microsoft Windows/Apache 2.2/Mongrel and Red Hat/Apache 2.2/Mongrel with various adapter(odbc, oledb) and tabular data stream translators. When testing several operating systems, adapters, manipulators, etc there were inevitable issues between the different setups. One of the most common issues was the adapter specific handling of dates. Depending on the adapter’s TDS(tabular data stream), dates can be returned as strings or date objects. This issue made our project less flexible as we were having to modify view code here and there. To solve the issue we extended the rails core and created a DBI override class in the lib directory of our project.

To do this, add a core_ext folder inside of your project’s lib directory. Next, add a ruby file called core_ext.rb; contents shown below.

#Include each of the files in the core_ext directory
Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each{ |file| require(file) }

Once your core_ext folder and file are setup in lib you’ll need to tell the environment.rb file to include your core extenders. Append the following line to your environment.rb file.

require 'core_ext'

Once our extensions are visible in the environment we can add our date time handler for dates where DBI is the project adapter. Add a file called DBI.rb in the core_ext directory. Contents shown below.

require "date"
module DBI
  class Date
      def to_friendly_str(options = {})
       t = self.to_time
       t.to_friendly_str(options) rescue self
      end

      def strftime(options = {})
        t = self.to_time
        t.strftime(options) rescue self
      end
   end
end

 

You’ll notice a non-standard method called “to_friendly_str”. You can replace this with stftime or create a custom date string handler like we did. I’ve added to_friendly_str below if you want to add it to the core_ext directory in addition to the DBI module or you can place it in your application controller. Enjoy!

def to_friendly_str(options = {})
# Attempt to init a new time object
# from this string then call
# to friendly_str on it.
    t = Time.parse(self)
    t.to_friendly_str(options) rescue self
end