Costco_normaltrevorturk

http://twitter.com/trevorturk

Automated Postgresql backups with pg_dump

Annoyingly, postgres makes is very annoying to pass in your password when using pg_dump. There's a way around it, though...

PGPASSWORD=YOUR_PASS pg_dump -Fc --username=YOUR_USER --host=YOUR_HOST YOUR_DB_NAME > YOUR_BACKUP_FILE
Reveal More
Added almost 2 years ago

upstart script for couchdb-lucene that creates a pidfile for monit, god, etc

# /etc/init/couchdb-lucene.conf

description "CouchDB-Lucene server"
script
  cd /PATH/TO/couchdb_lucene
  exec sudo -u couchdb ./bin/run
end script
post-start script
  # hack to create a pid file
  CDB_PID=`status couchdb-lucene |egrep -oi '([0-9]+)$' |head -n1` 
  echo $CDB_PID >/var/run/couchdb-lucene.pid
end script

# monit

check process couchdb_lucene with pidfile /var/run/couchdb-lucene.pid
group database
start program = start couchdb-lucene
stop  program = stop couchdb-lucene
if failed host 127.0.0.1 port 5985 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
depends on couchdb
Reveal More
Added almost 2 years ago

CLICK THAT BUTTON

# The Sinatra app behind http://clickthatbutton.com/ running on http://heroku.com

# I can't figure out how to increment the "clicks" counter and get the db to return 
# the new total without doing another request... holler if you know how...
# I tried to use Sequel and ended up getting pissed off somehow, so reverted to
# using Active Record and laying in the hammock.

require 'rubygems'
require 'sinatra'
require 'erb'
require 'active_record'

dbconfig = YAML.load(File.read('config/database.yml'))
ActiveRecord::Base.establish_connection dbconfig['production']

class CreateClicks < ActiveRecord::Migration
  def self.up
    create_table :clicks do |t|
      t.integer :clicks, :default => 0, :null => false
    end
    Click.create!(:clicks => 0)
  end
end

class Click < ActiveRecord::Base
end

get '/' do
  response.set_cookie('click', 0) if request.cookies['click'].nil?
  @clicks_total = Click.first.clicks
  erb :index
end

post '/' do
  Click.first.increment!(:clicks)
  Click.first.clicks.to_s
end
Reveal More
Added almost 2 years ago

Quick and dirty "voting" with basic cookie tracking

class VotesController < ApplicationController
  
  def create
    @video = Video.find(params[:id])
    @voted_for = cookies[:voted_for] ? cookies[:voted_for].split(",") : []
    if @voted_for.include?(@video.id.to_s)
      render :text => "You already voted for #{@video}!"
    else
      render :text => "Thanks for voting for #{@video}!"
      cookies[:voted_for] ||= []
      cookies[:voted_for] = cookies[:voted_for] << "#{@video.id},"
      Video.increment_counter(:votes, @video.id)
    end
  end
end
Reveal More
Added almost 2 years ago

Automatic slug generation advanced with de-dupe technology

# I'm not sure if there's a better way to do this, but it works...

# The tests look like:

  test "deals with dupe slugs automatically" do
    v1 = Video.make(:name => "Nick Vegas")
    v2 = Video.make(:name => "Nick Vegas")
    v3 = Video.make(:name => "Nick Vegas")
    assert_equal "nickvegas", v1.slug
    assert_equal "nickvegas2", v2.slug
    assert_equal "nickvegas3", v3.slug
  end

# The model and relevant code looks like:

class Video < ActiveRecord::Base
  before_validation :generate_slug
  validates_presence_of :slug
  validates_uniqueness_of :slug
  
  def generate_slug
    slug = name.parameterize.gsub('-', '')
    if Video.find_by_slug(slug)
      counter = 2
      until Video.find_by_slug("#{slug}#{counter}").nil?
        counter += 1
      end
      slug = "#{slug}#{counter}"
    end
    self.slug = slug
  rescue
    # use validations to catch errors
  end   
end
Reveal More
Added almost 2 years ago

Cron job and sprinkle script for weekly CouchDB compaction

# http://github.com/crafterm/sprinkle
# http://couchdb.apache.org/
# http://wiki.apache.org/couchdb/API_Cheatsheet

# Requires the rubygems: rubygems right_aws right_http_connection json 

package :couchdb_compaction do
  config_file = '/etc/cron.weekly/couchdb_compaction'
  config_text = %q[
#!/usr/bin/ruby
%w(rubygems right_aws right_http_connection json).each { |f| require f }

dbs = JSON.parse %x(curl -sS 'http://localhost:5984/_all_dbs')

dbs.each do |db|
  %x(curl -X POST -sS 'http://localhost:5984/#{db}/_compact')
  %x(curl -X POST -sS 'http://localhost:5984/#{db}/_view_cleanup')

  design_docs = JSON.parse %x(curl -sS 'http://localhost:5984/#{db}/_all_docs?startkey=%22_design%2F%22&endkey=%22_design0%22')

  design_docs.each do |doc|
    name = doc[1][0]['id'].gsub('_design/', '') rescue nil
    %x(curl -X POST -sS 'http://localhost:5984/#{db}/_compact/#{name}') if name
  end
end
].lstrip

  push_text config_text, config_file do
    pre :install, "touch #{config_file}"
    post :install, "chmod 0755 #{config_file}"
  end

  verify do
    has_file config_file
  end
end
Reveal More
Added about 2 years ago

Re: Rack middleware to 301 urls with trailing slashes

# Modified from the original to store the regexp in a constant, to simplify 
# the removable of the trailing slash, and to utilize Rack to rebuild the URL.

module Rack
  class TrailingSlash

    HAS_TRAILING_SLASH = %r{^/(.*)/$}

    def initialize(app)
      @app = app
    end

    def call(env)
      if env['PATH_INFO'] =~ HAS_TRAILING_SLASH
        env['PATH_INFO'].chomp!('/')
        [301, {"Location" => Rack::Request.new(env).url}, []]
      else
        @app.call(env)
      end
    end

  end
end

# NOTE: real-world experience shows this may not work if used behind Varnish, 
# because the port will be changed due to the proxy_pass...
Reveal More
Added about 2 years ago

no-www Rack Middleware

# Websites should have a canonical address. This address shouldn’t begin with “www” because 
# it’s unnecessary and wasteful. See http://no-www.org/ for details. This middleware catches 
# requests that begin with “www” and redirects them to the more reasonable non-www address.

# Rails Usage

# Put this file in lib/, and then add the following to config/environment.rb:

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

class NoWWW
 
  STARTS_WITH_WWW = /^www\./i
  
  def initialize(app)
    @app = app
  end
  
  def call(env)
    if env['HTTP_HOST'] =~ STARTS_WITH_WWW
      [301, { 'Location' => Rack::Request.new(env).url.sub(/www\./i, '') }, ['Redirecting...']]
    else
      @app.call(env)
    end
  end
  
end
Reveal More
Added about 2 years ago

How Flowcoder uses pygments.appspot.com

require 'net/http'
require 'uri'

class Post < ActiveRecord::Base  
  before_save :pygmentize_body
  
  def pygmentize_body
    self.pygmentized_body = Net::HTTP.post_form(URI.parse('http://pygments.appspot.com/'), {'lang'=>language, 'code'=>body}).body
  end
    
end

# Then you can call @post.pygmentized_body to get the stored HTML with syntax highlighting without doing another request
Reveal More
Added over 2 years ago

Example for Python Pygments via Ruby via Google App Engine

# Flowcoder is now using http://pygments.appspot.com/ to get pygments code syntax highlighting

require 'net/http'
require 'uri'

lang = 'python'
code = 'print "Hello World"'

request = Net::HTTP.post_form(URI.parse('http://pygments.appspot.com/'), {'lang'=>lang, 'code'=>code})
puts request.body
Reveal More
Added over 2 years ago

nginx launchd item for mac os x

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>nginx</string>
<key>Program</key>
<string>/opt/nginx/sbin/nginx</string>
<key>KeepAlive</key>
<true/>
<key>NetworkState</key>
<true/>
<key>StandardErrorPath</key>
<string>/opt/nginx/logs/error.log</string>
<key>LaunchOnlyOnce</key>
<true/>
</dict>
</plist>
Reveal More
Added over 2 years ago

Heroku Backup

alias herokubackup='cd ~/code/backups &&
heroku db:pull sqlite://my_app.db --app my_app &&
heroku db:pull sqlite://my_other_app.db --app my_other_app &&
DATE=`date +%Y-%m-%d` &&
mkdir $DATE &&
mv *.db $DATE'
Reveal More
Added over 2 years ago
Post Code