KZAK: an open source web-based jukebox

Posted by Trevor in General, KZAK on February 08, 2010

I'm happy to announce that I've made my latest side-project open source. It's called KZAK. It's a simple web-based jukebox that you can use to share and listen to music with your friends.

The feature set is pretty limited right, but I hope to continue to improve things over time. I'm already encouraged by how quickly some of my friends have taken to the app, and I think you'll enjoy it - even in this early form.

So far you can:

  • Invite people to use the site via email
  • Upload mp3, mp4, and m4a (iTunes) tracks with an upload queue and progress
  • Listen to the uploaded music as a playlist, even in an inactive browser tab

Like I said, it's pretty basic (invite, upload, listen) but surprisingly functional. Plus, I'm using all kinds of interesting stuff behind the scenes, which is why I really wanted to share the code ;)

To begin with, we've got a Rails app that's using the latest and greatest in user authentication technology: Devise. If you're using something like restful_authentication or Authlogic, I implore you to take a look at Devise. It's a phenomenal improvement from these other two popular options, and it's being actively supported by José Valim, the latest Rails committer. Essentially, it's a Rails Engine that sits on top of Warden - a generalized Rack authentication framework. This combination is extraordinarily flexible and easy to use. It's opinionated (in a good way) while simultaneously doing a good job of staying out of the way. It introduces very little code into your application, and the source is well documented, well tested, and easy to follow. A++ highly recommended.

To handle the file uploads, I've switched from Paperclip to CarrierWave. While Paperclip has (and continues) to serve me well in many applications I work with, I really appreciate the modular approach that CarrierWave takes. It's agnostic as to which of the popular S3 clients you use, supporting both aws/s3 and right_aws. It's also ORM agnostic and not tightly coupled to Active Record. The tight coupling of Paperclip has caused us some grief at work, and I'm also confused about the state of Paperclip's support for aws/s3 and right_aws. So, I was happy to find this new project, and the maintainer Jonas Nicklas seems to be an extremely responsive and helpful dude, which is always good thing. The code looks great, and I've had an easy time working with this library so far.

In concert with CarrierWave, I'm also using the venerable SWFUpload to support upload queues and progress meters. I'm absolutely baffled as to why this kind of thing isn't easy/possible to support without Flash, but here we are. Of course, I have a fallback "regular upload form" that still uses some ajax to make things a little easier. There are a few blog posts and tutorial applications around on GitHub that helped me get SWFUpload working with Rails and jQuery, and I'm happy to put back out an example application that other people can refer to if they're interested in supporting upload queues and/or upload progress meters.

Next, to support audio playback while I work on supporting html5 properly, I'm using the extremely awesome SoundManager 2. Unfortunately, this is another part of the infrastructure using Flash, but the features and functionality of SoundManager are really something special. I've only scratched the surface of what this library can do, but I'm already enjoying it quite a bit. If you're working with jQuery and SoundManager, you may find the KZAK source code worth perusing. You might also take a look at Adrien Gibrat's plugin, which is a cool jQuery plugin that packs a lot of functionality.

Also running in the background of KZAK is a Twitter-style following/unfollowing system that I haven't exposed much of yet. It's basically the same system that's powering Flowcoder. You can check out this example app I made if you're interested in seeing that on its own. Currently, all users in the system follow (and are followed by) all of the other users. I plan to allow for "unfollowing" users some time soon, which will allow for some healthy splintering of the community in the case that you're not interested in everything that everyone is uploading.

Finally - and perhaps best of all - KZAK is fully compatible with and easy to install on Heroku. All you need is an S3 account and you're ready to get started with a web-based jukebox for you and your friends for free.

http://github.com/trevorturk/kzak

Anyway, please feel free to dig around the source code if you're interested in any of this. I think there's a lot of good stuff in there, especially considering that the Ruby portion of the app is clocking in at under ~250 LOC right now. Thanks, open source community ;)

Cloudfront: no-brainer CDN support for S3

Posted by Trevor in General on February 08, 2010

Amazon's CloudFront is a phenomenal addition to their S3 file-hosting service.

Amazon CloudFront is a web service for content delivery. It integrates with other Amazon Web Services to give developers and businesses an easy way to distribute content to end users with low latency, high data transfer speeds, and no commitments.

Amazon CloudFront delivers your static and streaming content using a global network of edge locations. Requests for your objects are automatically routed to the nearest edge location, so content is delivered with the best possible performance. Amazon CloudFront works seamlessly with Amazon Simple Storage Service (Amazon S3) which durably stores the original, definitive versions of your files. Like other Amazon Web Services, there are no contracts or monthly commitments for using Amazon CloudFront – you pay only for as much or as little content as you actually deliver through the service.

If you're using S3 and you're not using CloudFront, you should take a moment to check it out. You'll be surprised at how little work it takes to set up, how much it speeds up your assets serving, and how little it costs.

CloudFront is a part of the Amazon Console now, so it's very easy to set up. All you need to do is to create a distribution, which means enabling CloudFront for a specific S3 bucket and choosing a CNAME that you'll serve your assets from. Then, you need to set up the CNAME in your DNS configuration on GoDaddy and you're done.

The following two screenshots illustrate the process.

Step one is to creating the distribution in Amazon's Console:

Note the Domain Name and CNAMEs sections in the lower half of the screen. I've chosen the CNAME of "s3.kzak.org" because I want my S3 bucket to be aliased such that URLs will look like this:

http://s3.kzak.org/example.jpg

CloudFront has provided me with the domain name that I need to provide to GoDaddy. Since I'm using their "Total DNS" option, all I have to do is add the CNAME like so:

Notice that the CNAME of "s3" is set to the domain name that CloudFront provided me.

These changes seem to take about 30 minutes to percolate through the internets, but that's all it takes to get started with CloudFront.

For bonus points, you may want to read up about using multiple asset hosts in Rails and apply this technique in your applications for additional throughput.

Flowcoder: Share, refactor, and tweet code snippets

Posted by Trevor in General, Ruby/Rails on February 08, 2010

I just realized that I never posts about our entry into the Rails Rumble last year.

Flowcoder: An Evolution of the Code Snippet Site

Coded and designed by @gbuesing, @scottymac, and @trevorturk for @railsrumble in 2009.

Flowcoder has what you would expect from a code snippet side: multiple language support, raw code view, and support for embedding on other sites.

What was missing for us and what we really wanted was a site that featured not just the code, but the people creating the code. Just as we glean interesting tidbits about people's lives from Twitter, we wanted to learn from our favorite coders by being able to follow the kind of code snippets they create. We wanted to share our own code snippets and have others refactoring them: to fix, optimize, and make them better, and learn in the process. And we wanted to be kept informed: when your code is refactored on Flowcoder, you'll see an @reply from @flowcoderbot with some information and a link. This closes the loop in a casual, low bandwidth fashion and highlights the advantage of using Twitter as both an identity and notification system.

no-www Rack Middleware

Posted by Trevor in General on November 05, 2009

I'm pleased to present my submission to the CodeRack contest: no-www.

This middleware catches requests that begin with “www” and redirects them to the more reasonable "non-www" address.

For example: http://www.example.com -> http://example.com

While such redirects might better be performed from within an Apache or nginx config, some hosts (i.e. Heroku) don't give you access to configure the server as such.

If you're unfamiliar with the no-www movement, the philosophy is simple. Websites should have a canonical address. This address shouldn’t begin with “www” because the use of "www" is unnecessary and wasteful. See http://no-www.org/ for details.

And, without further ado:

If you know what Rack is, you problably already know how to use this. Still, an example usage for a Rails app wouldn't hurt. Start by copying the above middleware into lib/no_www.rb. Then, configure your application to use the middleware by placing the following in config/environment.rb:

 
Rails::Initializer.run do |config|
  config.middleware.use “NoWWW” if RAILS_ENV == ‘production’
end

No more www.

Installing Varnish with nginx, Passenger, and Monit on Ubuntu 8.10 intrepid

Posted by Trevor in Ruby/Rails on October 22, 2009

Varnish is a state-of-the-art, high-performance HTTP accelerator. I first came to know about it thanks to Heroku, where they use it to provide built-in HTTP Caching.

As their docs describe, using Varnish is easy:

# This tells the cache (Varnish) to serve the page for 300 seconds (5 minutes).
 
class MyController < ApplicationController
  def index
    response.headers['Cache-Control'] = 'public, max-age=300'
    render :text => "Rendered at #{Time.now}"
  end
end

Simply setting the "Cache-Control" header like so allows you to serve up a page extremely quickly because requests completely bypass your application logic, database, and all of that related overhead and read straight from the cache.

If you're serving up the same page to all visitors, then setting up Varnish HTTP caching is a no-brainer. If you're serving up pages that are mostly the same for all users but have a custom header or something, you can still take advantage of the caching speed boost if you're willing to investigate the ins and outs of ESI and/or serving partials with Javascript. If you're serving pages that are different for each user, then you're out of luck :)

So, using Varnish for HTTP acceleration is great, but unfortunately for me the version of Ubuntu (8.10 intrepid) that we're using has a painfully out of date package in aptitude. If you're already running Varnish, you can check to make sure you're using a relatively recent release by running varnishd -V. If you see anything less than 2.0.4, you should seriously consider upgrading.

Thanks to the helpful people on the Varnish mailing lists, I was able to get things up and running by doing the following:

Note that there’s a new version of Varnish out now. The 2.0.4 tag is still pretty good, but you should check all the available tags and decide if you’d rather use a newer version. If so, you’ll have to adjust the installation instructions found at the top of this post slightly.

Note that the .deb files generated by the “dpkg-buildpackage” command may be different from those generated at the time this post was written. The basic steps still apply, though.

apt-get update
apt-get install subversion autotools-dev automake1.9 libtool autoconf libncurses-dev xsltproc quilt
cd /tmp
svn co http://varnish.projects.linpro.no/svn/tags/varnish-2.0.4
cd varnish-2.0.4/varnish-cache
dpkg-buildpackage
cd ..
dpkg -i libvarnish1_2.0.4-6_i386.deb
dpkg -i varnish_2.0.4-6_i386.deb

You can then use /etc/init.d/varnish to stop/start/restart the service.

But, we're not done yet. Since it took me a while to get the whole app server stack configured, I thought it might help someone else out if I covered the rest of the steps it took to get Varnish working properly with my Ruby application.

You can get nginx installed with Ruby Enterprise Edition and Passenger by following the excellent documentation on the Phusion website.

I might suggest, however, doing the installation like this in order to get the latest (secure) version of nginx. Even before that, you'll probably want to install Ruby Enterprise Edition, which I like to do the old fashioned way.

You may also be interested in this example nginx init.d config, which allows you to use nginx as you would if installed from a package. Make sure to consider doing some kind of log rotation with this kind of setup as well.

...

Now that you're using the fantastic nginx web server, you'll want to configure it to listen to port 8080, so that Varnish can listen to port 80 and forward any requests that aren't in its cache to the backend server (nginx). I'll just post the complete config we're using, and you can pick out the relevant details for your case.

Some interesting things to note is that this setup is configured to use Sinatra, the lightweight Ruby web framework. If the application throws an exception, we're routing to the /error page. We're also using various other settings that you may or may not agree with. The important part with regard to Varnish and nginx cooperating, however, is that you set nginx to listen to port 8080 in your config file. My config is located in /opt/nginx/conf/nginx.conf:

worker_processes 1;
pid /var/run/nginx.pid;

events {
  worker_connections  1024;
}

http {
  access_log /var/log/nginx_access.log;
  error_log /var/log/nginx_error.log;
  passenger_root /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-2.2.5;
  passenger_ruby /opt/ruby-enterprise/bin/ruby;
  passenger_max_pool_size 10;
  include mime.types;
  default_type application/octet-stream;
  sendfile on;
  tcp_nopush on;
  keepalive_timeout 65;
  gzip on;
  gzip_comp_level 2;
  gzip_buffers 16 8k;
  gzip_disable "MSIE [1-6]\.";
  gzip_proxied any;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  server {
    listen 8080; # the important part!
    root /var/www/example/current/public;
    passenger_enabled on;
    passenger_use_global_queue on;
    rack_env production; # use rails_env for a rails app
    # serve static files without running more rewrite tests
    if (-f $request_filename) {
      break;
    }
    # disable site via capistrano (cap deploy:web:disable)
    if (-f $document_root/system/maintenance.html) {
      rewrite ^(.*)$ /system/maintenance.html break;
    }
    # expires headers
    location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ {
      expires max;
      break;
    }
  }
}

Now, I'm fairly new to using Varnish, so perhaps someone can advise me about how to better configure things, but I'll cover how I did it. Varnish comes with a few example configs loaded up in /etc/default/varnish. I ended up using the following:

NFILES=131072
MEMLOCK=82000
INSTANCE=$(uname -n)
DAEMON_OPTS="-a :80 -f /etc/varnish/default.vcl -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"

You can review the examples provided and see how you want to go about it, though.

Once you're all set with the general config, you'll need to provide a VCL config. I'm putting ours in /etc/varnish/default.vcl and it looks like this:

backend default {
  .host = "127.0.0.1";
  .port = "8080";
}

# Warning: read the following before using this config:
# http://varnish.projects.linpro.no/wiki/VCLExampleCacheCookies

sub vcl_recv {
  unset req.http.cookie;
}

The first part tells Varnish to forward any requests that aren't in its cache to a webserver running on localhost port 8080. That's nginx!

The second part unsets any cookies that are sent along with any requests. You won't want to do this unless you're serving the same pages for all users for your entire application. If you aren't careful here, you can very easily end up serving pages meant for one user to another. Be careful!

In my case this works fine because we're serving a site with no user-specific actions or views. It's all public. You're case might be different. Perhaps you can cache things like static files (images, etc) or certain areas of your application. Maybe you have a CMS with an admin interface that can't be cached, but with publically viewable pages that could be cached. I dunno. In any case, you should definitely read more about this on the Varnish wiki.

Finally, since we're using Monit to monitor the health of our systems, I'll throw in an example config that covers SSH, nginx, and Varnish. This Monit config would email you using a Google Apps Domain if there was a problem. You probably wouldn't want to use this as-is, but it should serve as a decent starting point for you to create your own. We've got the config in /etc/monit/monitrc:

# Alerts
set daemon 120
set logfile syslog facility log_daemon
set mailserver smtp.gmail.com port 587
    username "noreply@example.com" password "sldkjkfdsj"
    using tlsv1
    with timeout 30 seconds
set alert tech@example.com with reminder on 30 cycles
set httpd port 2812
allow example:slkdjlskdjflskjd

# SSH
check process sshd with pidfile /var/run/sshd.pid
start program "/etc/init.d/ssh start"
stop program "/etc/init.d/ssh stop"
if failed port 22 protocol ssh then restarts
if 5 restarts within 5 cycles then timeout

# nginx
check process nginx with pidfile /var/run/nginx.pid
start program = "/etc/init.d/nginx start"
stop  program = "/etc/init.d/nginx stop"
if failed host 127.0.0.1 port 8080 then restart
if cpu is greater than 40% for 2 cycles then alert
if cpu > 60% for 5 cycles then restart
if 10 restarts within 10 cycles then timeout

# Varnish
check process varnish with pidfile /var/run/varnishd.pid
start program = "/etc/init.d/varnish start"
stop  program = "/etc/init.d/varnish stop"
if failed host 127.0.0.1 port 80 then restart
if cpu is greater than 40% for 2 cycles then alert
if cpu > 60% for 5 cycles then restart
if 10 restarts within 10 cycles then timeout

That's all folks!

Pygments

Posted by Trevor in General on September 16, 2009

I'm pleased to announce the immediate availability of http://pygments.appspot.com. It's an unofficial API for the Pygments syntax highlighting library. It's designed to provide syntax highlighting for web applications that don't have Python installed. You can think of it as an HTTP interface for Pygments.

To use it, simply POST to http://pygments.appspot.com with "lang" and "code" parameters in the body. You'll receive pygmentized HTML back, which you can store for later display on your site.

I'm using it so that I can host Flowcoder on Heroku. I was really impressed with the ease of getting this Pygments app running on Google App Engine. GAE is very much like a Python version of Heroku, which means it's awesome.

I'm hoping that this little project will spike my interest in learning a bit more about Python, which actually doesn't seem as evil as all my Ruby friends have made it out to be :P

The source code is on github, in case you're curious about how this all works.

Enjoy!

http://pygments.appspot.com

Passenger with nginx on Mac OS X

Posted by Trevor in Ruby/Rails on September 16, 2009

Setting up nginx with Passenger support turns out to be fairly easy.

Start by making sure you have the most recent version of Passenger, then install the nginx module. This will actually install and compile nginx with the Passenger module enabled, which is handy. Choose the recommended/default options when the installer prompts you.

sudo gem update passenger
sudo passenger-install-nginx-module

Then, open up the nginx config file:

mate /opt/nginx/conf/nginx.conf

Add the following line to the top of the file:

daemon off;

This will prevent the "502 Bad Gateway" error you may see otherwise. I'm not sure why this is necessary, but I read about it here, and it seems to do the trick. nginx specifies that this should only be used for development, though.

Next, find the http { block, which should start around line 15 or so. You'll want to add a server { block within the http { block for each of your Rails/Rack applications, like so:

server {
   listen 80;
   server_name eldorado.local;
   root /Users/trevorturk/Code/eldorado/public;
   passenger_enabled on;
   rails_env development;
}

You'll need an entry in your hosts file if you don't already have one. Simply open up the file:

mate /etc/hosts

...and add lines for each of the apps you plan to run, like so:

127.0.0.1 eldorado.local 

Now, we can set up a launchd item, so that nginx will start up automatically after a system reboot. Create a new plist file by opening it up in TextMate:

mate /System/Library/LaunchDaemons/nginx.plist

...and paste the following code in, which was kindly provided for us by this helpful person:

Then, run the following command to load it:

launchctl load -F /System/Library/LaunchDaemons/nginx.plist

Now, you can reboot your system and make sure it's all working as expected by visiting http://eldorado.local, or whatever address you've configured your application to be on.

I believe this nginx installation will override the existing Apache installation you may have running. This doesn't bother me, so I opened up my System Preferences -> Sharing prefpane and unchecked the Web Sharing box, so Apache is no longer running. If you have any ideas about how to keep both services running cooperatively, please do let me know.

Update: Here are some additionally configuration options I'm using, which I cobbled together from various sources after Googling for things like "nginx, rails, gzip, expires" and such. Their powers combined, and I seem to have a YSlow-approved setup.

Just above your server { block, around line 40, add the following:

gzip on;
gzip_buffers 16 8k;
gzip_disable "MSIE [1-6]\.";
gzip_proxied any;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

That should cover gzip well enough.

Then, amend the aforementioned server { block to include some far future expires goodness that takes advantage of the Rails asset_tag helpers:

server {
  listen 80;
  server_name eldorado.local;
  root /Users/trevorturk/Code/eldorado/public;
  passenger_enabled on;
  rails_env development;
  location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ {
      expires max;
      break;
  }
}

These two configuartion tweeks are, I believe, the rough equivalent of the technique previously discussed on this blog for Apache.

Of course, any additional suggestions, comments, or insights you may have would be most welcome. I'm new to this whole nginx thing, but I'm enjoying it so far.

Update: Here's an easy way to reload nginx, if you need to make a change to your conf. Make sure to have the following in your /opt/nginx/conf/nginx.conf file:

pid /var/run/nginx.pid;

Then, you can make an alias for the reload task in your ~/.bash_profile:

alias nr='sudo kill -HUP `cat /var/run/nginx.pid`'

In case you're interested, you can check out my full nginx.conf file for local development here:

http://gist.github.com/191331

Static: a super simple Rails CMS for Heroku

Posted by Trevor in Ruby/Rails on September 11, 2009

Static is a super simple Rails CMS built for Heroku. It supports file uploads to S3, makes image thumbnails, lets you make pages, has an optional admin password, and a customizable application layout that supports erb. It's really easy to install and deploy to Heroku. If you have an S3 account, you can get up and running in under 5 minutes.

I made this little app a few weekends back because it scratched a personal itch of mine. I maintain a few small "static" or "brochure" sites for friends, which means I get to do boring HTML updates whenever they have a new picture or video they want to add. I figured that I could do a little upfront work and let them to do the rest. So, I looked around for a simple Rails CMS, but I couldn't find anything simple enough. Thusly, Static was born.

It doesn't do much for you, but that's the point. You get a really simple little Rails app that lets you add pages, upload stuff, and wrap everything in a layout that can be updated online. If you ever need to add any cool new functionality (like displaying recent Twitter updates?) you can do it using Ruby/Rails. No more lame old hacked-together PHP sites ;) Static's well-tested, 175 line code base could be the solid foundation for a site that grows over time.

This thing does exactly and only what I need it to do, but I'm happy to accept patches and such. Give it a shot, fork away, and let me know if you have something good for me to pull.

http://github.com/trevorturk/static/

Enjoy!

Poor Man’s Heroku Backups

Posted by Trevor in Code, Ruby/Rails on September 11, 2009

Here's a quick and dirty way to back up all of your Heroku-powered databases using their Taps gem with one easy command. It works well enough for my simple needs, but any improvements you've got would be most welcome!

Just add the following to your ~/.bash_profile, and you're good to go:

El Dorado on Heroku

Posted by Trevor in El Dorado, Ruby/Rails on July 09, 2009

I'm pleased to announce that El Dorado is now compatible with Heroku, the instant Ruby platform.

heroku

This means that deploying El Dorado is no longer a pain in the ass. It also means that you can get started with El Dorado for free. Just follow along with the installation and deployment instructions in the README and you're good to go.

If you need help along the way, drop by the support site: http://eldorado.heroku.com/

Enjoy!

Config vars and Heroku

Posted by Trevor in El Dorado, Ruby/Rails on June 25, 2009

I don't really care for the suggested approach in the Heroku docs for setting configuration variables locally. I have an open-source project that I'm working to get onto Heroku, so I decided to do a little work to come up with a solution that I prefer. I think this would work well for open source projects, as well as projects with multiple developers.

Here's the basic idea:

You have a config file that contains all of your local configuration variables. It looks a lot like database.yml.

 
# config/config.yml
 
development:
  session_key: example_development
  session_secret: ESl6X3oKM1i1RRrD2QLwUUzz9jr1zxNO
  domain: http://example.com
 
test:
  session_key: example_test
  session_secret: vrwPpJTvwnMVLP1wTSgqigSl7PMI7QcE
  domain: http://example.com
 
production:
  session_key: # any string identifying your app
  session_secret: # a random, secret string at least 32 characters long
  domain: # http://example.com
  mailer: # noreply@example.com
 

You perform a little trickery in environment.rb to prefer the Heroku ENV storage of config vars (in the production environment), but you fall back to your config.yml if the config vars aren't found in ENV (in the development and test environments).

 
# config/environment.rb
 
Rails::Initializer.run do |config|
  require 'yaml'
 
  # support yaml and heroku config vars, preferring ENV for heroku
  CONFIG = (YAML.load_file('config/config.yml')[RAILS_ENV] rescue {}).merge(ENV)
 
  config.action_controller.session = {
    :key => CONFIG['session_key'],
    :secret => CONFIG['session_secret']
  }
end
 

Then, you create a rake task (rake heroku:config) that can be used to send all of the config vars for your production environment up to Heroku. This task can be invoked once to set things up, but can also be run again if you need to make any additions or changes.

 
# lib/tasks/heroku.rake
 
namespace :heroku do
  task :config do
    puts "Reading config/config.yml and sending config vars to Heroku..."
    CONFIG = YAML.load_file('config/config.yml')['production'] rescue {}
    command = "heroku config:add"
    CONFIG.each {|key, val| command << " #{key}=#{val} " if val }
    system command
  end
end
 

This way, you've got all of your config vars stored with the project (.gitignored, of course)...

 
# .gitignore
 
/tmp/**/*
/log/*
*.log
/tmp/restart.txt
/config/config.yml
/config/database.yml
/db/*.sqlite3
 

...and you can easily set what you need on Heroku, like so:

 
$ rake heroku:config
Reading config/config.yml and sending config vars to Heroku...
Adding config vars:
  session_key => example_production
  session_secret => 1WlkMkYYi5611vtF...0ZMS2G3Xl67s4lEIK4sj65
  domain => http://example.com
  mailer => noreply@example.com
Restarting app...done.
 

The result is a pretty nice, I think.

You can see the installation and deployment instructions for my open source project El Dorado if you're curious about the overall flow.

I'd love to get some feedback on this approach, but I really like it so far :)

GitHub Protip: Follow other users

Posted by Trevor in Code on June 11, 2009

Inspired by this post, I thought I'd share a tip that helps me get the most out of GitHub.

Don't just follow the projects that you're interested in — follow other users. Here's a list of people that I'm following. They're constantly turning me on to new and interesting projects, because I get to see everything they're working on, and everything they're following.

 

Dig around the users that I follow, check out what they're been up to, and try it out. If you find that your feed becomes a bit much to manage, try subscribing to your personal RSS feed. There's a link on the home page when you're logged in.

Thanks, GitHub. You're the best.

Automatically Rotate your Log Files in Development

Posted by Trevor in Ruby/Rails on June 11, 2009

I'm trying to save hard drive space, since I've got this super small (and fast?) SSD hard drive on the way. I noticed that I was using a TON of space to store totally worthless logs for my Rails apps. Now, I know I could set up proper log rotation, but I don't feel like going through the trouble for my local machine.

Here's a quick tip I picked up here that will set your logs to automatically rotate in the test and development environments. Just add the following line to these files:

  • config/development.rb
  • config/test.rb
config.logger = Logger.new(config.log_path, 2, 20.megabytes)

Make sure you've got these in your .gitignore file as well:

/log/*
*.log

That will keep your log files under control, but with plenty of room for digging in if need be.

Speed up your Apache/Passenger Rails app in 2min

Posted by Trevor in Ruby/Rails on June 11, 2009

Here's a quick tip for speeding up your Apache/Passenger powered Rails app. It'll take you about 2 minutes, and I guarantee you'll notice the speed-up.

  • SSH onto your VPS
  • Run the following commands: "a2enmod expires" and "a2enmod deflate"

Now, open up your Apache vhost config for your Rails app. Add the following:

Then, restart Apache by running: "/etc/init.d/apache2 restart"

This will gzip your html, css, and javascript. It'll also add far future expires headers for the appropriate cacheable filetypes. There's no downside, and it only takes a second. Bang for buck.

Edit: Check the comments for some possible downsides... ;)

Time Bomb Test

Posted by Trevor in Ruby/Rails on April 05, 2009

Sometimes you come across something in the Rails changelog that suggests a config change before upgrading to the next version. Sometimes you only have time to put some code together quickly, but you know that you really should go back and refactor it soon. How and where can you remind yourself about this stuff?

I'm not sure where I originally came across this concept, but I think it's worth sharing again anyway. I'll even give it a name this time. Time Bomb Tests: easy cheesy reminders you can put into your test suite. They'll sit there like little time bomb reminders - exploding only when you need them to.

 
# test/integration/time_bomb_test.rb
 
require 'test_helper'
 
class TimeBombTest < ActionController::IntegrationTest
 
  test "stuff to do with next rails upgrade" do
    flunk if Rails.version != '2.2.2'
    # rename application.rb to application_controller.rb
    # etc...
  end
 
  test "stuff I'm putting off today, but really should do eventually" do
    flunk if Time.now > Time.parse('5/1/2009')
    # optimize that thing marked HACK in the user model
    # etc...
  end
end
 

Update: Check out jeremymcanally's deprecate, which appears to have been partially inspired by this post. It allows you to deprecate (primarily) test code after a certain date, version, or other arbitrary condition is met.