Capistrano deploy to multiple locations

Pretty simple, but wanted to log here so I can look this up in the future…

I wanted to deploy to both a stage and a live site. Here’s how that went down:

First I installed the capistrano-ext gem. Second, I edited my Capfile to look like this:

1
2
3
require 'capistrano/ext/multistage'
set :default_stage, "beta"
set :stages, %w(beta live)

Third, I created a deploy folder and added my two recipes there. beta.rb looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
load 'deploy' if respond_to?(:namespace) # cap2 differentiator
 
default_run_options[:pty] = true
 
# be sure to change these
set :user, 'username'
set :domain, 'beta.example.org'
set :application, 'fundastache'
 
# the rest should be good
set :repository,  "#{user}@#{domain}:git/#{application}.git" 
#set :repository,  "/home/#{user}/git/#{application}.git" 
set :deploy_to, "/home/#{user}/#{domain}" 
set :deploy_via, :remote_cache
set :scm, 'git'
set :branch, 'master'
set :git_shallow_clone, 1
set :scm_verbose, true
set :use_sudo, false
 
server domain, :app, :web
 
namespace :deploy do
  task :restart do
    run "touch #{current_path}/tmp/restart.txt" 
  end
end

The live recipe looks almost identical.

Now when I

1
cap live deploy

the site is deployed to the live environment and when I

1
cap beta deploy

or simply

1
cap deploy

the site is deployed to the beta site.

Posted: April 23rd, 2010 | Author: jay | Filed under: Code | Tags: , , , , , | No Comments »

I need to promote this more.

Posted: April 5th, 2010 | Author: jay | Filed under: Uncategorized | No Comments »

Curl command to test JSON posts

1
curl -i -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d '{"user":{"username_or_email":"username","password":"password"}}' http://fas/test_json_post
Posted: April 4th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , | No Comments »

Lost sleep over JSON and Rack::PostBodyContentTypeParser

I’ve been fighting this issue the last couple nights. I wrote earlier about how Rack::PostBodyContentTypeParser can automagically turn a posted JSON object into a Rack / Sinatra params hash. So, I wrote some tests to make sure this was the case and moved on. Well, it turns out in real life things weren’t working and I couldn’t figure out why. Everything looked cool, but the hash wasn’t getting set when I did an AJAX call in the browser – everything was empty. I looked at everything, from the server, to the JS library, to the browser, to setting different content types in prototype.js etc… UGH!

The short of it is that Rack::PostBodyContentTypeParser requires exactly application/json in order to automagically turn the posted JSON object into Rack params and prototype.js (and jquery.js were adding an encoding type of charset=UTF-8 so the entire header entry was coming across as this CONTENT_TYPE: application/json; charset=UTF-8. So, as a fix, I’m just including the Rack::PostBodyContentTypeParser in the Sinatra application with one small change. Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
module Rack
 
  # A Rack middleware for parsing POST/PUT body data when Content-Type is
  # not one of the standard supported types, like <tt>application/json</tt>.
  #
  # TODO: Find a better name.
  #
  class PostBodyContentTypeParser
 
    # Constants
    #
    CONTENT_TYPE = 'CONTENT_TYPE'.freeze
    POST_BODY = 'rack.input'.freeze
    FORM_INPUT = 'rack.request.form_input'.freeze
    FORM_HASH = 'rack.request.form_hash'.freeze
 
    # Supported Content-Types
    #
 
    ################## turned into regex so it matches type with encoding data...
    #APPLICATION_JSON = 'application/json'.freeze
    APPLICATION_JSON = /^application\/json/.freeze
 
    def initialize(app)
      @app = app
    end
 
    def call(env)
      case env[CONTENT_TYPE]
      when APPLICATION_JSON
        env.update(FORM_HASH => JSON.parse(env[POST_BODY].read), FORM_INPUT => env[POST_BODY])
      end
      @app.call(env)
    end
 
  end
end

I tested that this worked by writing the following:

1
2
3
4
5
6
7
8
9
10
def test_post_as_json_converts_to_params
  # sanity check that post with normal params works...
  post '/test_params_as_json', :param1=>"param one"
  assert_equal last_response.body,"params[:param1]=param one"
  post '/test_params_as_json', {:param1=>"param one"}.to_json, "CONTENT_TYPE"=>"application/json"
  assert_equal last_response.body,"params[:param1]=param one"
  # this is the problem, adding a charset to the content type seems to breaks rack-contrib/post_body_content_type_parser.rb
  post '/test_params_as_json', {:param1=>"param one"}.to_json, "CONTENT_TYPE"=>"application/json; charset=UTF-8"
  assert_equal last_response.body,"params[:param1]=param one"    
end
Posted: April 4th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , , , , | 4 Comments »

Maybe I’ll start embedding code from gist…

Let’s see how this looks…

Posted: April 1st, 2010 | Author: jay | Filed under: Uncategorized | No Comments »

Couldn’t get that last thing to work so keeping it simple (stupid)

This could undoubtedly be more elegant, but it’s late and I want it to work now. May take another stab at it later…

TODO: limit the content types and only allow rendering if they are ok.

Setting up a before filter:

1
2
3
4
5
6
7
before do
  # remove and grab the file extension
  request.path_info.sub! %r{\.([^\./]+)$}, ''
  @format=$1 || 'html'
  @charset=mime_type($1) || 'text/html'
  content_type @charset, :charset => 'utf-8'
end

and using a case statement:

1
2
3
4
5
6
7
8
9
10
11
get "/home" do
  case @format
  when 'html'
    @stylesheet='home.css'
    haml :home, :layout=>:layout_simple
  when 'js'
    "{'js':true}"
  else
    pass
  end
end
Posted: April 1st, 2010 | Author: jay | Filed under: Code | Tags: , , , , | No Comments »