Tips for Ruby Developers

Page last updated:

This page has information specific to deploying Rack, Rails, or Sinatra apps.

App Bundling

You must run Bundler to create a Gemfile and a Gemfile.lock. These files must be in your app before you push to Cloud Foundry.

Rack Config File

For Rack and Sinatra, you must have a config.ru file. For example:

require './hello_world'
run HelloWorld.new

Asset Precompilation

Cloud Foundry supports the Rails asset pipeline. If you do not precompile assets before deploying your app, Cloud Foundry will precompile them when staging the app. Precompiling before deploying reduces the time it takes to stage an app.

Use the following command to precompile assets before deployment:

$ rake assets:precompile

Note that the Rake precompile task reinitializes the Rails app. This could pose a problem if initialization requires service connections or environment checks that are unavailable during staging. To prevent reinitialization during precompilation, add the following line to application.rb:

config.assets.initialize_on_precompile = false

If the assets:precompile task fails, Cloud Foundry uses live compilation mode, the alternative to asset precompilation. In this mode, assets are compiled when they are loaded for the first time. You can force live compilation by adding the following line to application.rb.

Rails.application.config.assets.compile = true

Running Rake Tasks

Cloud Foundry does not provide a mechanism for running a Rake task on a deployed app. If you need to run a Rake task that must be performed in the Cloud Foundry environment, rather than locally before deploying or redeploying, you can configure the command that Cloud Foundry uses to start the app to invoke the Rake task.

An app start command is configured in the app manifest file, manifest.yml, using the command attribute.

If you have previously deployed the app, the app manifest should already exist. There are two ways to create a manifest. You can manually create the file and save it in the app root directory before you deploy the app for the first time. If you do not manually create the manifest file, the cf CLI will prompt you to supply deployment settings when you first push the app, and will create and save the manifest file for you, with the settings you specified interactively. For more information about app manifests, and supported attributes, see Deploying with Application Manifests.

Example: Invoking a Rake database migration task at app startup

The following is an example of the “migrate frequently” method described in the Migrating a Database in Cloud Foundry topic.

  1. If a Rakefile does not exist, create one and add it to your app directory.
  2. In your Rakefile, add a Rake task to limit an idempotent command to the first instance of a deployed app:

    namespace :cf do
      desc "Only run on the first application instance"
      task :on_first_instance do
        instance_index = JSON.parse(ENV["VCAP_APPLICATION"])["instance_index"] rescue nil
        exit(0) unless instance_index == 0
      end
    end
    
  3. Add the task to the manifest.yml file, referencing the idempotent command rake db:migrate with the command attribute.

    ---
    applications:
    - name: my-rails-app
      command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
    
  4. Update the app using cf push.

Rails 3 Worker Tasks

This section shows you how to create and deploy an example Rails app that uses a worker library to defer a task that a separate app executes.

The guide also describes how to scale the resources available to the worker app.

Note: Most worker tasks do not serve external requests. Use the --no-route flag with the cf push command, or no-route: true in the app manifest, to suppress route creation and remove existing routes.

Choose a Worker Task Library

You must choose a worker task library. The table below summarizes the three main libraries available for Ruby / Rails:

Library Description
Delayed::Job A direct extraction from Shopify where the job table is responsible for a multitude of core tasks.
Resque A Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later.
Sidekiq Uses threads to handle many messages at the same time in the same process. It does not require Rails, but integrates tightly with Rails 3 to simplify background message processing. This library is Redis-backed and semi-compatible with Resque messaging.

For other alternatives, see https://www.ruby-toolbox.com/categories/Background_Jobs.

Create an Example App

For the purposes of the example app, we will use Sidekiq.

First, create a Rails app with an arbitrary model called “Things”:

$ rails create rails-sidekiq
$ cd rails-sidekiq
$ rails g model Thing title:string description:string

Add sidekiq and uuidtools to the Gemfile:

source 'https://rubygems.org'

gem 'rails', '3.2.9'
gem 'mysql2'

group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'uglifier', '>= 1.0.3'
end

gem 'jquery-rails'
gem 'sidekiq'
gem 'uuidtools'

Install the bundle.

$ bundle install

Create a worker (in app/workers) for Sidekiq to carry out its tasks:

$ touch app/workers/thing_worker.rb
class ThingWorker

  include Sidekiq::Worker

  def perform(count)

    count.times do

      thing_uuid = UUIDTools::UUID.random_create.to_s
      Thing.create :title =>"New Thing (#{thing_uuid})", :description =>
"Description for thing #{thing_uuid}"
    end

  end

end

This worker will create n number of things, where n is the value passed to the worker.

Create a controller for “Things”:

$ rails g controller Thing
class ThingController < ApplicationController

  def new
    ThingWorker.perform_async(2)
    redirect_to '/thing'
  end

  def index
    @things = Thing.all
  end

end

Add a view to inspect our collection of “Things”:

$ mkdir app/views/things
$ touch app/views/things/index.html.erb
nil

Deploy the App

This app needs to be deployed twice for it to work, once as a Rails web app and once as a standalone Ruby app. The easiest way to do this is to keep separate Cloud Foundry manifests for each app type:

Web Manifest: Save this as web-manifest.yml:

---
applications:
- name: sidekiq
  memory: 256M
  instances: 1
  host: sidekiq
  domain: ${target-base}
  path: .
  services:
  - sidekiq-mysql:
  - sidekiq-redis:

Worker Manifest: Save this as worker-manifest.yml:

---
applications:
- name: sidekiq-worker
  memory: 256M
  instances: 1
  path: .
  command: bundle exec sidekiq
  no-route: true
  services:
  - sidekiq-redis:
  - sidekiq-mysql:

Since the url “sidekiq.cloudfoundry.com” is probably already taken, change it in web-manifest.yml first, then push the app with both manifest files:

$ cf push -f web-manifest.yml
$ cf push -f worker-manifest.yml

If the cf CLI asks for a URL for the worker app, select none.

Test the App

Test the app by visiting the new action on the “Thing” controller at the assigned url. In this example, the URL would be http://sidekiq.cloudfoundry.com/thing/new.

This will create a new Sidekiq job which will be queued in Redis, then picked up by the worker app. The browser is then redirected to /thing which will show the collection of “Things”.

Scale Workers

Use the cf scale command to change the number of Sidekiq workers.

Example:

$ cf scale sidekiq-worker -i 2

Use rails_serve_static_assets on Rails 4

By default Rails 4 returns a 404 if an asset is not handled via an external proxy such as Nginx. The rails_serve_static_assets gem enables your Rails server to deliver static assets directly, instead of returning a 404. You can use this capability to populate an edge cache CDN or serve files directly from your web app. The gem enables this behavior by setting the config.serve_static_assets option to true, so you do not need to configure it manually.

Add Custom Libraries

If your app requires external shared libraries that are not provided by the rootfs or the buildpack, you must place the libraries in an ld_library_path directory at the app root.

Note: You must keep these libraries up-to-date. They do not update automatically.

The Ruby buildpack automatically adds the directory <app-root>/ld_library_path to LD_LIBRARY_PATH so that your app can access these libraries at runtime.

Environment Variables

You can access environments variable programmatically. For example, you can obtain VCAP_SERVICES as follows:

ENV['VCAP_SERVICES']

Environment variables available to you include both those defined by the system and those defined by the Ruby buildpack, as described below.

BUNDLE_BIN_PATH

Location where Bundler installs binaries.

BUNDLE_BIN_PATH:/home/vcap/app/vendor/bundle/ruby/1.9.1/gems/bundler-1.3.2/bin/bundle

BUNDLE_GEMFILE

Path to app Gemfile.

BUNDLE_GEMFILE:/home/vcap/app/Gemfile

BUNDLE_WITHOUT

The BUNDLE_WITHOUT environment variable causes Cloud Foundry to skip installation of gems in excluded groups. BUNDLE_WITHOUT is particularly useful for Rails apps, where there are typically “assets” and “development” gem groups containing gems that are not needed when the app runs in production

For information about using this variable, see http://blog.cloudfoundry.com/2012/10/02/polishing-cloud-foundrys-ruby-gem-support.

BUNDLE_WITHOUT=assets

DATABASE_URL

The Ruby buildpack looks at the database_uri for bound services to see if they match known database types. If there are known relational database services bound to the app, the buildpack sets up the DATABASE_URL environment variable with the first one in the list.

If your app depends on DATABASE_URL being set to the connection string for your service, and Cloud Foundry does not set it, you can set this variable manually.

$ cf set-env my_app_name DATABASE_URL mysql://b5d435f40dd2b2:ebfc00ac@us-cdbr-east-03.cleardb.com:3306/ad_c6f4446532610ab

GEM_HOME

Location where gems are installed.

GEM_HOME:/home/vcap/app/vendor/bundle/ruby/1.9.1

GEM_PATH

Location where gems can be found.

GEM_PATH=/home/vcap/app/vendor/bundle/ruby/1.9.1:

RACK_ENV

This variable specifies the Rack deployment environment: development, deployment, or none. This governs what middleware is loaded to run the app.

RACK_ENV=production

RAILS_ENV

This variable specifies the Rails deployment environment: development, test, or production. This controls which of the environment-specific configuration files will govern how the app will be executed.

RAILS_ENV=production

RUBYOPT

This Ruby environment variable defines command-line options passed to Ruby interpreter.

RUBYOPT: -I/home/vcap/app/vendor/bundle/ruby/1.9.1/gems/bundler-1.3.2/lib -rbundler/setup

View the source for this page in GitHub