Posterous theme by Cory Watilo

Sample Capistrano Recipe with Assets Precompiling

Dear Developer,

Sub: Full Sample Capistrano Recipe for Rails 3.1

Capistrano provides for easy production deployment. Automation of deployment procedure with Capistrano recipe significantly reduces time spent and chances of human errors on subsquent app deployments. We were amazed by reduction of re-deployment times by well over 70% of developer's time!

Here is a cap recipe sample for rails 3.1.0 app for reference. We hope that you will really enjoy deployment of your rails app, with a neat Capistrano recipe of your own.

First, you should setup a secure ssh configuration with public/private RSA key (recommended). We are on RackSpace (Slicehost), and thankfully they have a neat blog to explain how to do this. With RSA your local machine get authenciated with server in easy and secure way for future deployment. 

Here are the steps:

SSH Configuration

Install ssh on server

Change the default port

$ sudo nano /etc/ssh/sshd_config

// Create local keys

$ ssh-keygen -t rsa

// Add public key on server

$ .ssh/authorized_keys

// Make sure to start the server

$ sudo /etc/init.d/ssh restart

Capistrano Receipe

Once into the root directory of your project run capify:

And then prepare your deploy.rb as follows. This capistrano receipe is with unicorn and svn repository.

The scm_verbose when set to true display all the svn commands. This is very useful when you want to know what latest file that has been updated from svn server and with its version information.

Set :use_sudo, false. This makes sure that deployment works without asking for user password.

Since you're on Rails 3.1.0 so before :deploy:assets:precompile, place :bundle_install; This make sure all gems and dependecies are installed before assets are compiled and dumped into the public directory.

..root/config/deploy.rb

# ========================================================
# REQUIRED VARIABLES
# ========================================================

# Name of project
set :application, "domain.com"
set :domain, "domain.com"

# ========================================================
# SCM OPTIONS
# ========================================================
set :scm, :subversion          # or :git
set :scm_user, "username"      # optional
set :scm_password, "password"  # optional
set :repository, "https://subversion.repository.com/project"
set :scm_verbose, true

# ========================================================
# SSH OPTIONS
# ========================================================
set :user, "ssh_user"
set :use_sudo, false
set :port, ssh-port

# ========================================================
# ROLES
# ========================================================
# Modify these values to execute tasks on a different server.
role :web, application
role :app, application
role :db,  application, :primary => true

# ========================================================
# CAPISTRANO OPTIONS
# ========================================================
set :deploy_via, :remote_cache
set :rails_env, :development
default_run_options[:pty] = true
set :runner, user
set :group, "admin"
set :deploy_to, "/project/staging"
set :pid, "/project/staging/shared/pids/unicorn.pid"

# This make sure the bundle runs with the task else it gives error
require 'bundler/capistrano'

set :unicorn_cmd, "unicorn  "

# ========================================================
# Project CAPISTRANO TASKS
# ========================================================

desc "BUNDLE INSTALL- installs the necessary prerequisites ..."
task :bundle_install, :roles => :app do
  run "cd #{release_path} && bundle install --deployment"
end

before :"deploy:assets:precompile", :bundle_install;

namespace :deploy do

  desc "Start Unicorn Server."
  task :start, :roles => :app do
   run  " cd #{current_path} && #{unicorn_cmd} -D "
  
  end

  desc "stop Unicorn Server."
  task :stop, :roles => :app do
  kill_processes_matching "unicorn master -D"
  end

def kill_processes_matching(name)
 run "ps -ef | grep '#{name}' | grep -v grep | awk '{print $2}' | xargs kill || echo 'no process with name #{name} found'"
end


  desc "Restart Unicorn processes"
  task :restart, :roles => :app do
    stop
    start
  end

end

# ========================================================
# RECIPE ENDS HERE
# ========================================================

That's it. Hope you'll find it useful.

Cheers,

@bubbles team

Rails 3.1.0 and Assets Pipeline - How to Serve Images, Javascript and Stylesheets?

Dear Rails Developer,

Sub: Assets pipeline.

So everyone is excited about Rails 3.1.0. Yes, the assets pipeline is quite awesome, and this has been discussed at length at several places already. However, for the folks trying it new there are some neat things and gotchas to be aware of. Assets pipeline does fall short of expected dryness, when it comes to including or NOT including some javascript on a particular page. And well, besides that this post is to help save some development time.

Here are some tips for assets:

The image paths inside stylesheets:

Among the few obstacles that I encountered was difficulty in serving images via CSS classes on the production server. We realized that serving images on production server is a more articulate process than serving images on a development or testing environment. On production, fingerprinting is done on all asset_paths and the cache of static files is dumped into public folder. The latest compiled dump is used to serve all assets.

The image_paths need to be absolutely accurate on production server. Or else we see "image error" on Firebug even though the image was served correctly during development. The best and most foolproof way is explicity mention the path of the image:

url("/assets/your-image-folder/cute-alien.png")

Remember it is just "/assets/your-image-folder/cute-alien.png" and not "/assets/images/image-folder1/cute-alien.png". Just leave out the images from in-between even though inside the assets directory there are three folders images, javascripts and stylesheets, and you'll feel the impulse to include the folder name.

If you use a style.css.scss.erb file extension to include images with something like this (asset_data_uri  method):

url(<%= asset_path "img/main-assets/cute-alien.png" %>)

then please be aware that style.css.scss cannot become a SASS partial like _style.css.scss.erb, or else there will be a compilation error in the parent stylesheet. The @import call in parent will fail to find _style.css.scss because the partial remains uncompiled at that stage in the directory.

Also in desperation please don't drop images in your public folder because such assets would not be served either. In production mode, rails 3.1 hasn't been able to finger-print image-assets (the ones you dropped into public folder), and thus left untochued by the application. Such references to image will eventually return a 404 error on the browser as failed img_URL_paths.

Place all assets into their designated places only, namely -

  1. ../app/assets/images
  2. ../lib/assets/images
  3. ../vendor/assets/images

Also I am yet to discover whether or not images of a 404/500 static pages (that were orginally created by $ Rails New Appname command in public folder) containing img_paths via css class or img_tag are served on production or not. As per my last deployment, images of static error templates were NOT served for the same reason that such images in public folder were not acknowledged by the rails app.

Javascript manifest files:

On @bubbles we have many js files some of which we did not want to include on every page. These js were meant only for some controller/actions. During the Release Candidate (rc) days of rails 3.1, I was expecting the manifest files to have some kind of capability to add condition-matching for 'controller/action' and then generate right sized application.js javascript.

Unfortunately, that did not happen. I lost quite some amount of development time to make it work but finally gave up on the fact that manifest files, even after having converted to .js.erb extension, do not have any means/method to include itself only on specific controller actions. Manifest files accept only directory trees (or filenames) which is like eating all the pills in the directory to cure a minor headache. A nice little suggestion on StackOverFlow was to make use of Jammit to organize, concatenate and compress the js files.

Hope this helps, to whomsoever it can =)

The focus of assets pipeline is to turn the tide towards making great looking web apps. It really pares off some burden of design from a designer on to a developer. We foresee great looking rails products and quicker delivery times due to assets pipeline!

Cheers,

@bubbles team

Ubuntu Commands to set up Rails3, Ruby 1.9.2 with Ruby Version Manager (RVM)

Guess most ruby enthusiasts are now moving on to Rails 3.0, but there is always something from the past application which holds us back. So here is some help for you to set it up on Ubuntu: Just follow these steps on your terminal:

ruby -v mkdir -p ~/.rvm/src/ && cd ~/.rvm/src && rm -rf ./rvm/ && git clone git://github.com/wayneeseguin/rvm.git && cd rvm && ./install rvm install 1.9.1 rvm list rvm 1.9.1 rvm 1.9.1 --default rvm system gem install tzinfo builder memcache-client rack rack-test rack-mount erubis mail text-format thor bundler i18n gem install rails --pre rails topscore cd topscore rails server gem install sqlite3-ruby rails generate scaffold game name:string rake db:migrate

and you are done. Also there is a lot of help given at Railscast just in case you get stuck somewhere. Get on Rails. Fast.

How to make an Ajax Call Synchronous in Rails 3.1

Dear Rails Developer,

Sub: Synchronized Ajax Calls

I know this is an edge case to discuss but there can be a scenario where synchronization of an Ajax call would be required. So this post to help some and save there time:

Let's say you have requested an Ajax request like this:

new Ajax.Request('/controller/action?username=********', {asynchronous:false, evalScripts:true, parameters:'page_offset=' + page_offset + '&authenticity_token=' + encodeURIComponent('e060znd6JcrMCU6Bf4ZZnfyBac4tl1YXQ6HuEHZGY58=')});

To set asynchronous:false in your link_to_remote add :type => synchronous as shown below:

<%=remote_function(:url => {:controller => "controller", :action => "action", :username => "praveen"}, :type => :synchronous, :with => "'page_offset=' + page_offset") -%>

Done. So now till the time the initial request is under process, everything else in the browser will wait until the request is completed. Synchronously. And then the browser will proceed to next step.

Regards,

@bubbles team

PS: We really love letters.