Tips for Ruby developers

Page last updated:

You can deploy Rack, Rails, or Sinatra apps with Cloud Foundry.

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.

To download Bundler, see Gem Bundler.

Rack config file

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

require './hello_world'
run HelloWorld.new

Asset pre compilation

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

To precompile assets before deployment, run:

rake assets:precompile

The Rake precompile task re-initializes the Rails app. This could pose a problem if initialization requires service connections or environment checks that are unavailable during staging. To prevent re-initialization during pre-compilation, 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.

For more information about app manifests and supported attributes, see Deploying with App Manifests.

Example: Invoking a Rake database migration task at App startup

See the following example of migrating a database schema using a Rake task.

For more information about migrating database schemas, see the Migrate a Database Schema section of the Services Overview topic.

To migrate a database schema using a Rake task:

  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 by running:

    cf push
    

Rails 3 worker tasks

Learn how to create and deploy an example Rails app that uses a worker library to defer a task that a separate app runs. It also describes how to scale the resources available to the worker app.

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. If you are using cf CLI v7 or later, be aware that the --no-route flag no longer unbinds all existing routes associated with the app.

Choose a worker task library

You must choose a worker task library.

The following table 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 Background Jobs on The Ruby Toolbox.

Creating an example app

The example app described in this section uses Sidekiq.

To create an example app:

  1. Create a Rails app with an arbitrary model named “Things” by running:

    rails create rails-sidekiq
    cd rails-sidekiq
    rails g model Thing title:string description:string
    
  2. 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'
    
  3. Install the bundle by running:

    bundle install
    
  4. In app/workers, create a worker for Sidekiq to carry out its tasks by running:

    touch app/workers/thing_worker.rb
    

    Create the worker as follows:

    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 create n number of things, where n is the value passed to the worker.

  5. Create a controller for “Things” by running:

    rails g controller Thing
    

    Create the controller as follows:

    class ThingController < ApplicationController
    
      def new
        ThingWorker.perform_async(2)
        redirect_to '/thing'
      end
    
      def index
        @things = Thing.all
      end
    
    end
    
  6. Add a view to inspect our collection of “Things” by running:

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

    Create the view as follows:

    <%= @things.inspect %>
    

Deploying the app

You must deploy your example app twice for it to work, once as a Rails web app and once as a standalone Ruby app. One way to do this is to keep separate Cloud Foundry manifests for each app type.

To create separate manifests for each app type:

  1. Create a web manifest and save it as web-manifest.yml:

    ---
    applications:
    - name: sidekiq
      memory: 256M
      instances: 1
      host: sidekiq
      domain: ${target-base}
      path: .
      services:
      - sidekiq-mysql:
      - sidekiq-redis:
    
  2. Create a worker manifest and save it 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:
    
  3. Since the URL sidekiq.cloudfoundry.com is likely already taken, change it in web-manifest.yml first, then push the app with both manifest files by running:

    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.

Testing the app

To test the app:

  1. Visit 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 creates a new Sidekiq job which is queued in Redis, then picked up by the worker app. The browser is then redirected to /thing, which shows the collection of “Things”.

Scale workers

To change the number of Sidekiq workers:

  1. Run:

    cf scale sidekiq-worker -i WORKER-NUMBER
    

    Where WORKER-NUMBER is the number of Sidekiq workers you want.

Use railsservestatic_assets on Rails 4

By default, Rails 4 returns a 404 error 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 error.

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.

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 by running:

ENV['VCAP_SERVICES']

Environment variables available to you include both those defined by the system and those defined by the Ruby buildpack, as described in the sections below. For more information about system environment variables, see the App-Specific System Variables section of the Cloud Foundry Environment Variables topic.

BUNDLEBINPATH

This variable specifies the location where Bundler installs binaries.

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

BUNDLE_GEMFILE

This variable specifies the path to the app Gemfile.

For example: BUNDLE_GEMFILE:/home/vcap/app/Gemfile

BUNDLE_WITHOUT

The BUNDLE_WITHOUT environment variable instructs Cloud Foundry to skip gem installation in excluded groups.

Use this with Rails apps, where “assets” and “development” gem groups typically contain gems that are not needed when the app runs in production.

For example: BUNDLE_WITHOUT=assets

DATABASE_URL

Cloud Foundry examines the database_uri for bound services to see if they match known database types. If known relational database services are bound to the app, the DATABASE_URL environment variable is set using the first match in the list.

If your app depends on DATABASE_URL to be set to the connection string for your service and Cloud Foundry does not set it, use the cf set-env command to can set this variable manually.

For example:

cf set-env my-app-name DATABASE_URL mysql://example-database-connection-string

GEM_HOME

This variable specifies the location where gems are installed.

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

GEM_PATH

This variable specifies the location where gems can be found.

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

RACK_ENV

This variable specifies the Rack deployment environment. Valid values are development, deployment, and none. This governs which middleware is loaded to run the app.

For example: RACK_ENV=development

RAILS_ENV

This variable specifies the Rails deployment environment. Valid values are development, test, and production. This controls which of the environment-specific configuration files governs how the app is run.

For example: RAILS_ENV=production

RUBYOPT

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

For example: 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