04.25.08

Posted in Rails at 1:44 pm by jasonb

I wander into my local RadioShack for a simple RCA to S-Video adapter (or SVHS). After looking around, I ask the lady and she finds one for me. It looks unimpressive enough. I ponder a cable to plugin to it, since the original one being replaced was male to female and this was female to female. She starts to grab one of those expensive monster cable sets, but I waive her off.

Read the rest of “Okay, I am done with RadioShack forever” »

04.12.08

Posted in Rails at 12:23 am by jasonb

After hours of Googling and an ill timed browser reload while typing this the first time, I finally happened upon RoR ticket 10454 which details the problem I am having with inferred routes and STI models. I modified it to supposedly support any level of model nesting. Seems to work now. I inserted it into my environment.rb presently.

Read the rest of “Rails STI resouce routes routing” »

04.01.08

Posted in Rails at 12:35 pm by jasonb

If you were following the excellent has_many :through blog, you may find you can’t use with_scope in the methods defined on your association. Instead, just send :with_scope along.

Read the rest of “has_many :through and with_scope protected” »

10.18.07

Posted in Rails at 5:16 pm by jasonb

Nothing fancy. It works.

Read the rest of “ed2k helper with Ruby” »

08.16.07

Posted in Rails at 5:03 pm by jasonb

I download a prerelease of the latest Engines earlier in the summer with piston. My tests were failing in strange and magical ways. I spent quite a bit of time trying different things, then finally resorted to a fresh Rails app that I slowly populated with relevant files. Quickly I discovered the problem was my Engines plugin. I really thought I had the full release, but clearly not.

Read the rest of “piston saves!” »

08.06.07

Posted in Rails at 4:25 pm by jasonb

I find myself having to validate an email address in a couple of different models. I’ve had to refine the pattern a couple of times, but don’t always remember to do it in every place, which is silly anyway. Since I don’t feel the need to delve into a new validation, like a validates_email_address or whatever, the following lets me simply reuse an existing validation in multiple places.

Read the rest of “dry model validations with class_eval” »

07.24.07

Posted in Rails at 11:14 pm by jasonb

Oh, I have such love for plugins that copy files around in production. I especially love it when the Rails app doesn’t have permission to write to the filesystem — why would it in production? — and Mongrel simply goes away. Running Mongrel without backgrounding it with start-stop-daemon reveals the trickery in action.

Read the rest of “ActiveScaffold and Mongrel death in production” »

07.15.07

Posted in Rails at 11:07 pm by jasonb

There are a ton of possible upload progress solutions for Web applications that need them. I had been using the upload progress that came with Merb, but I had modify mup.js to make Ajax calls using mootools instead of Prototype. Ultimately the progress status wasn’t updating consistently, so I sought a pure mootools compatible solution.

Read the rest of “Flash Upload Progress for Rails with FancyUpload for mootools” »

06.04.07

Posted in Rails at 4:08 pm by jasonb

Never in my life have I been so thoroughly ecstatic with a telecom provider. (Of course the honeymoon is over. Embarq is highly unreliable for DSL. Worse service I have ever had thus far.) Last Wednesday I ordered service completely online using the Embarq Web site. It was straightforward and easy. It was possible to order a bare phone line with no services of any kind except high speed internet (ADSL). I didn’t have to fight the Web site to exclude stupid bundles — or in the case of Verizon or Bellsouth simply give up; none were forced upon me.

Read the rest of “Embarq DSL weak value!” »

03.27.07

Posted in Rails at 1:06 am by jasonb

I admit it. I am bad. I run raw SQL in my migrations. The dataset I am working with requires it of me. It must be punished. To aid in its punishment, I found a post explaining how to get at PostgreSQL’s COPY from within the Postgres Ruby driver.

Read the rest of “Rails Migrations and PostgreSQL COPY” »

02.01.07

Posted in Rails at 2:49 am by jasonb

Have you been experiencing the hurt of Capistrano failing?

Read the rest of “querying latest revision fails?” »

01.07.07

Posted in Rails at 7:53 pm by jasonb

Programming with Ruby and developing Web apps with Rails is fun; Obviously so, or you wouldn’t be reading about deployment issues. Deployment can be challenging and especially so if you come from more of a development background than a systems administration background. Fortunately, I’m tacking this from the latter camp, so I am going to present excerts of Capistrano deployment configure below.

Deployment Summary

My objective is to configure Capistrano to take a virgin box and install and configure all necessary services. Such a setup is no doubt specific to each environment.

The platform targeted is Debian GNU/Linux Sarge. The database server is PostgreSQL 8.1. The Web server is running Apache 2.2 using mod_proxy_balancer. The application server is Mongrel.

Two environments are targeted: QA and production.

Assumptions

For the process to proceed smoothly, a few assumptions are made about the configuration of each system, besides the target platform and decided upon software. First, it is assumed there is a deployment user account and that the deployment initiator has key trust with said account.

Second, it is assumed the deployment user has fairly extensive sudo access, which is to say it’s effectively root. Second, it is assumed that Subversion is your SCM and that it is available via the svn+ssh transport. (It would be trivial to change to WebDAV, though, assuming you have that configured.)

As an example of achieving the user configuration portion of this.

# adduser --system --home /home/deploy --shell /bin/bash --ingroup nogroup deploy
chmod u+w /etc/sudoers
echo "deploy  ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
chmod u-w /etc/sudoers

Configuration

The initial deployment environment must first be defined.

require 'lib/tasks/capistrano_svn_tags.rb'
 
deploy_to_env = ENV["RAILS_ENV"] ||= 'qa'
 
set :application, "vrl"
set :repository, "svn+ssh://nebula.gohideaway.com/home/svn/#{application}"
set :deploy_to, '/srv/rails'
 
set :svn_port, 5555
set :svn_user, 'jasonb'
 
set :db_name, "#{application}_#{deploy_to_env}"
set :db_user, 'thedbuser'
set :db_passwd, 'thedbpasswd'
set :db_allow_hosts, {'qa' => '10.0.1.0/24', 'production' => '127.0.0.1/32'}
 
set :mongrel_port, 8100
set :mongrel_servers, 3
 
ssh_options[:keys] = %w(/home/user/.ssh/id_deploy /home/user/.ssh/id_dsa)
ssh_options[:username] = 'local_user_with_svn_access'

Some options are from stock Capistrano, many are not.

I prefer to deploy by tag or branch rather than whatever features are creeping into trunk, so I have included capistrano_svn_tags.rb. Further, it’s common in many environments to have a staging or QA environment that’s essentially identical to the production environment. deploy_to_env is used later to determine which kind of deployment is desired.

The svn_port and svn_user options allow Subversion to tunnel its way back to my internal Subversion server using svn+ssh. Access is further restricted to a specific IP range via a firewall configuration. They’re used later in conjunction with a template installed in the deployment user’s .subversion/config configuration file.

The database options allow a database user and password to be created and fed into PostgreSQL. The /etc/postgresql/8.1/main/pg_hba.conf is further modified to ensure access via TCP is properly restricted. (listen_addresses may need to be tweaked in /etc/postgresql/8.1/main/postgresql.conf.)

Now, I must ensure the correct hosts are targeted and the appropriate rails_env is selected.

if deploy_to_env == 'qa'
        set :rails_env, 'qa'
        role :web, "deploy@qa.gohideaway.com"
        role :app, "deploy@qa.gohideaway.com"
        role :db,  "deploy@qa.gohideaway.com", :primary => true
else
        set :rails_env, 'production'
        set :checkout, 'export'
        role :web, "deploy@www.gohideaway.com"
        role :app, "deploy@www.gohideaway.com"
        role :db, "deploy@www.gohideaway.com", :primary => true
end

Building a Host

I chose to piggyback the host environment tasks to task setup.

task :before_setup do
        setup_core
end
 
task :after_setup do
        apache_conf
        mongrel_conf
end

The purpose of setup_core is simply to install all the necessary software for each node.

task :setup_core do
        setup_stack
        setup_web
        setup_app
        setup_db
end

For example, setup_web will install Apache 2.2 and enable several modules necessary for mod_proxy_balancer to function.

task :setup_web, :roles => [:web] do
        mods = %w{rewrite proxy_connect proxy_http proxy_balancer}
        current_task.servers.each do |host|
                sudo "apt-get -qq update"
                sudo "apt-get -qq install apache2"
                run <<-CMD
                        for mod in #{mods.join(' ')} ; do
                                if [ ! -h /etc/apache/mods-enabled/${mod}.load ] ; then
                                        sudo /usr/sbin/a2enmod $mod ;
                                fi
                        done
                CMD
                sudo "/etc/init.d/apache2 reload || true"
        end
end

More strangely, perhaps, is the configuration of PostgreSQL. Notice the nested quote action for the SQL. Illustrated is the only safe way of handling the quoting.

task :setup_db, :roles => [:db] do
        current_task.servers.each do |host|
                sudo "apt-get -qq update"
                hack = <<-HACK
                        if [ -f /var/lib/dpkg/info/ubuntu-minimal.list ] ; then
                                sudo apt-get -qq install postgresql-8.1 postgresql-client-8.1 ;
                        else
                                sudo apt-get -qq install postgresql-8.1 postgresql-client-8.1 ssl-cert/sarge-backports ;
                        fi
                HACK
                run hack
 
                # Check for role existence.
                #
                # On Debian it is necessary to assume the role of the
                # postgres user to have blanket access without a password
                # using a local UNIX domain socket.
 
                create_role = true
                cmd = <<-CMD
                        su - postgres -c "/usr/bin/psql -Upostgres -c
                        \\\"SELECT rolname FROM pg_roles WHERE rolname = '#{db_user}'\\\"
                         template1"
                CMD
                sudo cmd do |c,s,d|
                        if create_role
                                puts d
                                if d =~ /#{db_user}/ then create_role = false end
                        end
                end
                puts create_role
 
                cmd = <<-CMD
                        su - postgres -c "/usr/bin/psql -Upostgres -c
                        \\\"CREATE ROLE #{db_user} WITH PASSWORD '#{db_passwd}'LOGIN\\\"
                         template1"
                CMD
                if create_role
                        sudo cmd
                end
 

Later, a Debianized version of Mongrel is configured.

task :mongrel_conf, :roles => [:app] do
        # Obviously assumes you deploy from your Rails root.
        put(render(:template => File.read('config/mongrel.conf'),
                :servers => mongrel_servers,
                :port => mongrel_port,
                :railsroot => "#{deploy_to}/current",
                :env => rails_env),
                "#{deploy_to}/conf/mongrel.conf", :mode => 0640)
 
        sudo "ln -nsf #{deploy_to}/conf/mongrel.conf /etc/mongrel/sites-enabled"
        restart_mongrel
end

Clearly, Capistrano’s task system is quite flexible. My only disappointment is having to hop into my RAILS_ROOT to start my deployment, but then with my various configuration files checked into svn, it’s perhaps easier that way.

Other Magic

When deploying a tag, I must ensure that uploaded photos are not lost. Capistrano makes tasks like this fairly simple by providing shell access.

task :save_photos do
if rails_env == 'production' || rails_env == 'qa'
         cmd = <<-CMD
                 if [ ! -d #{deploy_to}/shared/photos ] ; then
                         sudo mkdir -p #{deploy_to}/shared/photos ;
                         sudo chown deploy:www-data #{deploy_to}/shared/photos ;
                         sudo chmod g+ws #{deploy_to}/shared/photos ;
                 fi ;
                 if [ ! -L #{deploy_to}/current/photos -a -d #{deploy_to}/current/photos ] ; then
                         echo "photos/ is a directory!" ;
                         exit 1 ;
                 fi ;
                 if [ ! -L #{deploy_to}/current/public/photos ] ; then
                         sudo ln -nsf #{deploy_to}/shared/photos \
                         #{deploy_to}/current/public/photos ;
                 fi ;
         CMD
         run cmd
end
end

Security Considerations

A number of steps have been taken in an attempt to secure the system.

The deploy system account with only SSH key trust permited for login is used strictly for deployment, as it requires sudo to perform some actions and is effectively a limted root shell as a result. Instead, Apache and Mongrel run as www-data. (In my configuration, su is granted to the deploy user via sudo, effectively providing ProgreSQL superuser access to deploy.)

The database connection is tunneled over TLS with a md5′d password for accessing the database over TCP. Only the postgres user has unchallenged local access, obtainable only by using su as root and assuming the euid of the postgres user.

12.22.06

Posted in Rails at 11:48 pm by jasonb

Tonight I have been finishing up a plugin heavily based upon Scott Becker’s AssetPackager based upon my own interpretations of Serving JavaScript Fast. Mostly, I changed the way packages were handled, inserting each revision into a versioned directory instead of altering the filename. Further, jsPacker.pl is now preferred over jsmin if it is present in RAILS_ROOT/tools.

Read the rest of “Rails Plugin: Asset Bundle” »

12.15.06

Posted in Rails at 12:03 am by jasonb

Finally, I found some time to install Ajax Scaffold plugin tonight. I did have to wait an hour while asking the perpetual question, Is rubyforge ever up? Eventually, it was, and installed the plugin I did.

Read the rest of “Ajax Scaffold, a Perfect Case for Rails Engines” »

10.05.06

Posted in Rails at 10:48 pm by jasonb

Before I could start using acts_as_wizard a few things had to be changed. First, core_extensions.rb defined,

Read the rest of “Fixes for acts_as_wizard plugin” »

« Previous entries ·