Ryan Kanno: The diary of an Enginerd in Hawaii

Everything you've ever thought, but never had the balls to say.

My LinkedIn Profile
Follow @ryankanno on Twitter
My Feed

Tag Archive » ‘Rails’

Update: Using Capistrano 2.5 to deploy Rails 2.3 to Webfaction

Update

Having been a Capistrano user for a few years, I absolutely love sweet, sweet automation. A few months ago, I wrote a blog about how to use Capistrano to deploy to WebFaction. However, since that post, the winds of change have swept through the Rails and Capistrano community with the release of Rails 2.3 and Capistrano 2.5. WebFaction’s Ruby installation precludes you from taking advantage of these great updates, so I’ve come up with a little update to my previous post.


Learn to Change, Change to Learn

To be able to deploy Rails 2.3 with Capistrano 2.5, we’ll first have to jump through a few hoops. Nice, easy hoops, mind you, but still hoops nonetheless.

Your own Ruby installation

You’ll have to install a custom Ruby installation into your WebFaction home directory. By following Step 1 here, you’ll have a working Ruby 1.8.7 installation and RubyGem 1.3. You’ll need these if you want to deploy a Rails 2.3 application. Also, install a version of Mongrel tied to your Ruby installation.

Note: Typically, I like to install custom installations into ~/opt/local/lib/.

Edit Autostart.cgi

You’ll have to make a few edits to a few files from my previous blog post.

Next, open up your favorite editor of choice (*cough*vi*cough*) and edit the autostart.cgi file. Jump to the end of the file and comment out the following line from my previous blog:

1
2
 
# os.system('/usr/local/bin/mongrel_rails start -c /home/<webfaction_username>/webapps-releases/<webfaction_app_name>/current -d -e production -P /home/<webfaction_username>/webapps/<webfaction_app_name>/log/mongrel.pid -p <port>')

and change it to the following:

1
2
 
 os.system('/home/<webfaction_username>/opt/local/lib/ruby1.8/lib/ruby/gems/1.8/bin/mongrel_rails start -c /home/<webfaction_username>/webapps-releases/<webfaction_app_name>/current -d -e production -P /home/<webfaction_username>/webapps/<webfaction_app_name>/log/mongrel.pid -p <port>')

Notice: We’re using the path to Mongrel tied to our custom Ruby installation! This might be different in your installation!

Edit the Capfile

In my previous blog, we placed a custom deploy.rb into the config directory. With the latest version of Capistrano, you no longer need to do this. Rather, place the following into a file called Capfile in the root of your Rails project.

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
 
load 'deploy'
 
set :webfaction_username, "<webfaction_username>"
set :webfaction_db_type, "<webfaction_db_type>"
set :webfaction_db, "<webfaction_db>"
set :webfaction_db_username, "<webfaction_db_username>"
set :webfaction_port, "<webfaction_port (get from autostart.cgi)>"
set :database_yml_template, "database.example.yml"
 
set :application, "test"
set :deploy_to, "/home/#{webfaction_username}/webapps-releases/#{application}"
 
set :scm, :subversion
set :scm_user, "<scm_username>"
set :scm_password, Proc.new { Capistrano::CLI.password_prompt("Subversion password for #{scm_user}: ") }
set :repository, Proc.new { "--username #{scm_user} --password #{scm_password} --no-auth-cache <http://path/to/your/svn/goes/here/>"} 
 
set :user, "#{webfaction_username}"
set :use_sudo, false 
 
set :domain, "<webfaction_domain>"
 
role :app, domain
role :web, domain
role :db,  domain, :primary => true
 
desc "Symlink public to what webfaction expects the webroot to be"
task :after_symlink, :roles => :web do
  run "ln -nfs #{release_path}/public /home/#{webfaction_username}/webapps/#{application}/"
end
 
namespace :deploy do
 
  # Taken from http://jonathan.tron.name/2006/07/15/capistrano-password-prompt-tips 
  # Thanks Jonathan! :)
  desc "Creates the database configuration on the fly"
  task :create_database_configuration, :roles => :app do
    require "yaml"
    set :production_db_password, proc { Capistrano::CLI.password_prompt("Remote production database password: ") }
 
    db_config = YAML::load_file("config/#{database_yml_template}")
    db_config.delete('test')
    db_config.delete('development')
 
    db_config['production']['adapter'] = "#{webfaction_db_type}"
    db_config['production']['database'] = "#{webfaction_db}"
    db_config['production']['username'] = "#{webfaction_db_username}"
    db_config['production']['password'] = production_db_password
    db_config['production']['host'] = "localhost"
 
    put YAML::dump(db_config), "#{release_path}/config/database.yml", :mode => 0664
  end
 
  after "deploy:update_code", "deploy:create_database_configuration"
 
  desc "Redefine deploy:start"
  task :start, :roles => :app do
    invoke_command "/opt/local/lib/ruby1.8/lib/ruby/gems/1.8/bin/mongrel_rails start -c #{deploy_to}/current -d -e production -P /home/#{webfaction_username}/webapps/#{application}/log/mongrel.pid -p #{webfaction_port}", :via => run_method
  end
 
  desc "Redefine deploy:restart"
  task :restart, :roles => :app do
    invoke_command "/opt/local/lib/ruby1.8/lib/ruby/gems/1.8/bin/mongrel_rails restart -c #{deploy_to}/current -P /home/#{webfaction_username}/webapps/#{application}/log/mongrel.pid", :via => run_method
  end
 
  desc "Redefine deploy:stop"
  task :stop, :roles => :app do
    invoke_command "/opt/local/lib/ruby1.8/lib/ruby/gems/1.8/bin/mongrel_rails stop -c #{deploy_to}/current -P /home/#{webfaction_username}/webapps/#{application}/log/mongrel.pid", :via => run_method
  end
end
Note: Change all the values in tags like <webfaction_username>, <webfaction_db>, <webfaction_db_username>, etc. to those values that fit your configuration!
Otherwise, this file in itself won’t do you any good.

Now, you should be able to run the standard Capistrano tasks to deploy your application to WebFaction with the latest version of Rails!

Explanation

Basically, the only thing I’ve done is shown you how to update your version of Ruby, RubyGems, Mongrel, and Capistrano to place nicely in WebFaction. This should allow you to run commands like ‘cap deploy:setup’, ‘cap deploy:update’ on your local machine and update your live code on WebFaction’s servers. Nothing too serious going on here! As always, feel free to use, steal, take, and/or copy anything on this blog. Hopefully somewhere, someone on the Interwebs will find these tips handy!

And if you find anything wrong with these scripts, don’t hesitate to leave a comment or email!

Voila! (Enjoy)

Popularity: 21% [?]

Tagged: , , , , .


Installing MIT Simile’s Timeline locally (w/ Rails integration)

Update: 5/24/2009

If you’re using a newer version of Simile’s Timeline, 2.3.1 as of this writing, and want to run it on your own local server, check out the comment made by Biju. Thanks Biju!

Update: 12/5/2007

Apparently, I’m still a rookie blogger and I forgot to mention that I was pulling from trunk (-r 8642). Don’t use the tags if you want the code below to work. :) Sorry about that neilo!

Since my past few blogs have been for the Django community, I’ll switch it up a little and talk about a visualization widget from those uber-smart kids at MIT.

Timeline

For one of my Rails prototypes at work, I decided to integrate Timeline; a pretty neat DHTML-based AJAXy widget for visualizing time-based events. Using a visual timeline is not only a lot ‘purrrrrtier’ than the mundane list-style displays, but it also gives a better relative perspective of how events overlap, their duration, etc.

In any case, I liked loved it, and I really wanted to use it.

Since I typically don’t have access to the Internet at work (I know, I know… a pseudo-developer without Internet access; welcome to my so-called life), I often have to download libraries and install them locally. Searching Timeline’s mailing list archives, I found one thread concerning the local installation of Exhibit.

Yet, nothing about Timeline.

So with that said, here’s the edits I made (kudos to Firebug developers). I would’ve created a patch file, but I was too lazy and the edits were too easy (sorry). :) Search for the following line in timeline-api.js (located in src/webapp/api directory in the downloadable distribution).

var url = useLocalResources ?
            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
            "http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js";

and edit it to the following:

//var url = useLocalResources ?
//            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
//            "http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js";
var url = (document.location.toString().indexOf('https://') != -1 ? "https" : "http") + "://" + window.location.href.split("/")[2] + "WEB_URL_TO /src/ajax/api/simile-ajax-api.js?bundle=false";

Basically, instead of using the supplied Jetty webserver, we’re just editing the url to your local installation of the file. Remember to change WEB_URL_TO to the path to the simile-ajax-api.js file in your own environment. Typically, one would put this file in a publicly accessible web folder named js, javascript, etc.

Voila!

As an added bonus, nowhere in Timeline’s documentation or examples does it indicate how to load inline event data. When I say inline, I mean dynamic data produced as a result of an action; in this case a search query. I want to be able to query on a set of dates and produce all event data points between those dates. Timeline’s typical use case is to load data from a javascript (.js) file. Personally, since the data is dynamic, I didn’t feel like writing a temp file publicly accessible by the web server or creating a REST action exposing the dynamic data; both of which are viable solutions, the latter more ideal than the former. I just wanted to write JSON inside of the rendered html file and load the Timeline. To do so, instead of coding the following (like in their cubism example):

      tl = Timeline.create(document.getElementById("tl"), bandInfos, Timeline.HORIZONTAL);
      tl.loadJSON("cubism.js", function(json, url) {
           eventSource.loadJSON(json, url);
      });

Using a rails example, this is what I included in my view:

<% if @include_timeline %>
    <%= javascript_include_tag 'PATH_TO/timeline-api.js?timeline-use-local-resources=true' %> 
    <script>
      var tl;
 
      var events = {
        <% if @events %>
        'dateTimeFormat': 'iso8601',
        'events': [
          <% @events.each_with_index do |event, i| %>
          {
            <% if event.start and event.end %>
             'start': '<%= event.start.iso8601 %>',
             'end'  : '<%= event.end.iso8601 %>',
            <% else %>
             'start': '<%= event.occurred.iso8601 %>',
            <% end %>
            'title': '<%= event.headline %>',
            'description': '<%= event.description %>'
          }<% if i != @events.length - 1 -%>, <% end -%>
          <% end %>
        ]
        <% end %>       
      };
 
      function onLoad() {
        var eventSource = new Timeline.DefaultEventSource(); 
        var theme = Timeline.ClassicTheme.create();
        theme.event.label.width = 250;
        theme.event.bubble.width=320;
        theme.event.bubble.height=220;
        var bandInfos = [
          Timeline.createBandInfo({
              width: "20%",
              intervalUnit: Timeline.DateTime.DAY,
              intervalPixels: 100,
              eventSource: eventSource,
              theme:theme
          }),
          Timeline.createBandInfo({
              width: "50%",
              intervalUnit: Timeline.DateTime.MONTH,
              intervalPixels: 100,
              eventSource: eventSource,
              theme:theme
          }),
          Timeline.createBandInfo({
              width: "30%",
              intervalUnit: Timeline.DateTime.YEAR,
              intervalPixels: 200,
              eventSource: eventSource,
              theme:theme
          })
        ];
        bandInfos[1].syncWith = 0;
        bandInfos[2].syncWith = 0;
        bandInfos[2].highlight = true;
        tl = Timeline.create(document.getElementById("timeline"), bandInfos);
        eventSource.loadJSON(events, '');
      }
      var resizeTimerID = null;
      function onResize() {
          if (resizeTimerID == null) {
              resizeTimerID = window.setTimeout(function() {
                  resizeTimerID = null;
                  tl.layout();
              }, 500);
          }
      }
    </script>
  <% end %>

Things that you should take note of:

  • I used Ruby’s DateTime iso8601 message to help pass a date that Timeline could understand.
  • I called eventSource.loadJSON(events, ”); where I passed in the events JSON array.

Hopefully, these two pointers can help you save some time integrating Timeline into your project! Since this is on my blog, feel totally free to take/use/steal/distribute/copy/modify any code you see fit. All I ask is if you find any bugs, have any comments, or can think of ways to make my ugly code cleaner – I’d love to hear from you. :)

Enjoy!

Popularity: 41% [?]

Tagged: , , , , , , , .


OSCON: Day 2

Morning Tutorial

Technical Management of Software Development with Uber Technical Lead @ Google, Alex Martelli

Mr. Martelli covered a gauntlet of topics pertaining to technical management including empowering your team, optimal team size, time management skills, and test-driven development. Even though his tutorial regurgitated a lot of the obvious, it’s nice to hear it being preached by important people at large corporations. What I found most useful in Mr. Martelli’s presentation was his extensive list of suggested reading material about management. I’ll post them when I get a chance to go over his slides. :)

Overall grade: A-

Afternoon Tutorial

Introduction to Rails with Glenn Vanderburg

Unlike the Ruby presentation from a day ago, the Introduction to Rails was everything I hoped the Ruby talk was going to be (and more). Even though Mr. Vanderburg only had three or so hours, he did a great job of covering quite a bit of material. Topics he covered included the model, the controller, filters, flash, caching, layouts, views, the various helpers, form handling, migration, routing, and testing (*whew*). Though he didn’t get into great detail on each subject, I felt that he covered enough to pique my interest. I actually went back to the hotel itching to code a Rails app.

Overall grade: A

Stay tuned for more updates from OSCON 2007!

Popularity: 7% [?]

Tagged: , , , , , , .


Powered by Wordpress. Stalk me.