Permalink
Fetching contributors…
Cannot retrieve contributors at this time
405 lines (287 sloc) 12.2 KB
---
title: Tips for Ruby Developers
owner: Buildpacks
---
<strong><%= modified_date %></strong>
This page has information specific to deploying Rack, Rails, or Sinatra
apps.
## <a id='bundler'></a>App Bundling ##
You must run <a href="http://gembundler.com/">Bundler</a> to create a `Gemfile`
and a `Gemfile.lock`.
These files must be in your app before you push to Cloud Foundry.
## <a id='config'></a>Rack Config File ##
For Rack and Sinatra, you must have a `config.ru` file. For example:
~~~ruby
require './hello_world'
run HelloWorld.new
~~~
## <a id='precompile'></a>Asset Precompilation ##
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.
Use the following command to precompile assets before deployment:
<pre class="terminal">
$ rake assets:precompile
</pre>
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`:
~~~ruby
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`.
~~~ruby
Rails.application.config.assets.compile = true
~~~
## <a id='rake'></a>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
the [Deploying with Application Manifests](../../devguide/deploy-apps/manifest.html) topic.
### <a id='migrate-ruby-db'></a>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]
(../../devguide/services/migrate-db.html#frequent-migration) topic.
1. If a Rakefile does not exist, create one and add it to your app directory.
1. 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
~~~
2. 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
~~~
3. Update the app using `cf push`.
## <a id='workers'></a>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.
<p class="note"><strong>Note</strong>: Most worker tasks do not serve external requests. Use the <code>--no-route</code> flag with the <code>cf push</code> command, or <code>no-route: true</code> in the app manifest, to suppress route creation and remove existing routes.</p>
### <a id='worker-libs'></a>Choose a Worker Task Library ###
You must choose a worker task library.
The table below summarizes the three main libraries available for Ruby / Rails:
<table border="1" class="nice">
<tr>
<th>Library</th>
<th>Description</th>
</tr>
<tr>
<td><a href="https://github.com/collectiveidea/delayed_job">Delayed::Job</a></td>
<td>A direct extraction from <a href="http://www.shopify.com/">Shopify</a> where the job table is responsible for a multitude of core tasks.</td>
</tr>
<tr>
<td><a href="https://github.com/defunkt/resque">Resque</a></td>
<td>A Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later.</td>
</tr>
<tr>
<td><a href="https://github.com/mperham/sidekiq">Sidekiq</a></td>
<td>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.</td>
</tr>
</table>
For other alternatives, see
[https://www.ruby-toolbox.com/categories/Background_Jobs](https://www.ruby-toolbox.com/categories/Background_Jobs).
### <a id='example-app'></a>Create an Example App ###
For the purposes of the example app, we use Sidekiq.
First, create a Rails app with an arbitrary model named "Things":
<pre class="terminal">
$ rails create rails-sidekiq
$ cd rails-sidekiq
$ rails g model Thing title:string description:string
</pre>
Add `sidekiq` and `uuidtools` to the Gemfile:
~~~ruby
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.
<pre class="terminal">
$ bundle install
</pre>
In `app/workers`, create a worker for Sidekiq to carry out its tasks:
<pre class="terminal">
$ touch app/workers/thing_worker.rb
</pre>
~~~ruby
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.
Create a controller for "Things":
<pre class="terminal">
$ rails g controller Thing
</pre>
~~~ruby
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":
<pre class="terminal">
$ mkdir app/views/things
$ touch app/views/things/index.html.erb
</pre>
```
<%= @things.inspect %>
```
#### <a id='deploy'></a>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.
One way to do this is to keep separate Cloud Foundry manifests for each
app type:
Web Manifest: Save this as `web-manifest.yml`:
~~~yaml
---
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`:
~~~yaml
---
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:
<pre class="terminal">
$ cf push -f web-manifest.yml
$ cf push -f worker-manifest.yml
</pre>
If the cf CLI asks for a URL for the worker app, select **none**.
### <a id='test'></a>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 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".
### <a id='scale'></a>Scale Workers ###
Use the `cf scale` command to change the number of Sidekiq workers.
Example:
<pre class="terminal">
$ cf scale sidekiq-worker -i 2
</pre>
## <a id='rails-4'></a>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 <a href="https://rubygems.org/gems/rails_serve_static_assets">`rails_serve_static_assets`</a>
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.
## <a id='custom-libraries'></a>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.
<p class="note"><strong>Note</strong>: You must keep these libraries up-to-date. They do not update automatically.</p>
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.
## <a id='env-var'></a>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. For more information about system environment variables, see the [Application-Specific System Variables](../../devguide/deploy-apps/environment-variable.html#app-system-env) section of the _Cloud Foundry Environment Variables_ topic.
### <a id='BUNDLE-BIN-PATH'></a>BUNDLE\_BIN\_PATH ###
Location where Bundler installs binaries.
Example: `BUNDLE_BIN_PATH:/home/vcap/app/vendor/bundle/ruby/1.9.1/gems/bundler-1.3.2/bin/bundle`
### <a id='BUNDLE-GEMFILE'></a>BUNDLE_GEMFILE ###
Path to app Gemfile.
Example: `BUNDLE_GEMFILE:/home/vcap/app/Gemfile`
### <a id='BUNDLE-WITHOUT'></a>BUNDLE_WITHOUT ###
The `BUNDLE_WITHOUT` environment variable instructs Cloud Foundry to skip
gem installation in excluded groups.
Use this with Rails applications, where "assets" and "development" gem groups typically contain gems that are not needed when the app runs in production.
Example: `BUNDLE_WITHOUT=assets`
### <a id='DATABASE-URL'></a>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.
Example:
<pre class="terminal">
$ cf set-env my-app-name DATABASE\_URL mysql://example-database-connection-string
</pre>
### <a id='GEM-HOME'></a>GEM_HOME ###
Location where gems are installed.
Example: `GEM_HOME:/home/vcap/app/vendor/bundle/ruby/1.9.1`
### <a id='GEM-PATH'></a>GEM_PATH ###
Location where gems can be found.
Example: `GEM_PATH=/home/vcap/app/vendor/bundle/ruby/1.9.1:`
### <a id='RACK-ENV'></a>RACK_ENV ###
This variable specifies the Rack deployment environment. Valid value are <code> development</code>, <code>deployment</code>, and <code>none</code>.
This governs which middleware is loaded to run the app.
Example: `RACK_ENV=development`
### <a id='RAILS-ENV'></a>RAILS_ENV ###
This variable specifies the Rails deployment environment. Valid value are <code>development</code>, <code>test</code>, and <code>production</code>. This controls which of the environment-specific configuration files governs
how the app is executed.
Example: `RAILS_ENV=production`
### <a id='RUBYOPT'></a>RUBYOPT ###
This Ruby environment variable defines command-line options passed to Ruby
interpreter.
Example: `RUBYOPT: -I/home/vcap/app/vendor/bundle/ruby/1.9.1/gems/bundler-1.3.2/lib -rbundler/setup`