A Simple Formula for Evaluating Risk
Having been on the startup roller-coaster for over two years a lot of people assume I have a high tolerance for risk. I don’t. However, I do have a fairly simple formula for evaluating any situation in my life.
Given the scenario, can you bear the worst possible outcome?
It’s not rocket-science. Most people over-complicate their risk evaluation by either immediately withdrawing out of fear, or spending hours enumerating the pros and cons.
Take a situation where you’re about to part with $10,000. What is the worst possible outcome? Perhaps it’s that you lose the $10k. So, what does that mean? Perhaps it won’t affect you at all. Maybe it will sting, but life will go on. Maybe it means that you’ll homeless and forced to sell your car. Maybe it means some thug will break your legs. Or, maybe the money doesn’t matter, but your reputation is on the line. Either way, define the worst possible outcome and answer the question, “can you bear it?”
Not Having a Plan B Makes Plan A More Successful
Today, I attended ProductCamp Austin, an unconference about Marketing and Product Management. One of the best presentations of the day was Entrepreneurship in a Down Economy by Yuen Yung, Co-founder and CEO of How Do You Roll. Yuen is responsible for the title of this post, as I found his quote quite meaningful, and humorous.
Yuen’s restaurant concept is basically Subway for sushi — you build your own sushi roll — and his mission is to “make the world a better place, one stomach at a time.” Yuen had no presentation, it was just him telling the story of how he found himself in the unexpected circumstance of starting a restaurant weeks after the economy started to take a nose dive. Investing his life savings, to the tune of a half million dollars, he had no other alternative then to keep moving forward towards Plan A. Banks had no money and he tapped out friends and family.
However, the down economy provided some benefits to Yuen, who believes that there are always two sides to every situation. He was able to hire over-qualified staff. Vendors were working to attract his business and accommodate his needs. His marketing budget was quickly lost to higher than estimated equipment costs. He rebounded by personally introducing himself to every customer, explaining his mission, and asking that they provide feedback and tell their friends.
It was interesting to hear Yuen talk about how he is applying Lean Startup principles to his restaurant business. Lean Startup has attracted a lot of interest from hi-tech and web startups, but the concepts of minimum viable product, customer driven development, and learning and reacting fast can easily be applied to any business.
After hearing Yuen talk, it’s clear he is going to be successful. He has charisma, is determined and dedicated to his mission, has integrity, and cares about people and building relationships. It also doesn’t hurt that his restaurant’s sushi rolls are delicious, inexpensive, and made to my exact specifications.
There is so much truth in Yuen’s words. To reach your end-goal as an entrepreneur, especially when bootstrapping your company, you have to commit yourself to your plan. Sure, you can make adjustments to Plan A along the way. The path is never a straight one. However, Plan B just might be a pessimistic distraction and a parachute that you open too early.
Easy Rails API Authentication Using restful-authentication
You’ve got a Rails application and you’d like to add an API. This tutorial assumes you are using restful-authentication.
Creating the API key
You’ll need to add a new column, api_key, to your users table. This field will store the unique API key used for authentication.
./script/generate migration AddApiKeyToUsers
class AddApiKeyToUsers < ActiveRecord::Migration def self.up add_column :users, :api_key, :string, :limit => 40, :default => "" end def self.down remove_column :users, :api_key end end
The API key is a simple SHA hash based on the current time and a random number — we need this to be unique. We’re not going to enable the API for a user by default, though you could easily do this using before_create. Instead, we’ll let the user enable or disable the API using the API Keys Controller, which we’ll create next.
Make the following changes to your app/models/user.rb file:
class User < ActiveRecord::Base def enable_api! self.generate_api_key! end def disable_api! self.update_attribute(:api_key, "") end def api_is_enabled? !self.api_key.empty? end protected def secure_digest(*args) Digest::SHA1.hexdigest(args.flatten.join('--')) end def generate_api_key! self.update_attribute(:api_key, secure_digest(Time.now, (1..10).map{ rand.to_s })) end end
Now, let’s create the API Keys Controller, which we’ll use to allow the user to create, re-generate, and delete their API Key. This effectively allows the user to enable and disable API access to their account.
./script/generate controller APIKeys
class APIKeysController < ApplicationController before_filter :login_from_cookie before_filter :login_required # Create or re-generate the API key def create current_user.enable_api! respond_to do |format| format.html { redirect_to edit_user_path(current_user) } end end # Delete the API key def destroy current_user.disable_api! respond_to do |format| format.html { redirect_to edit_user_path(current_user) } end end end
Add the resource to config/routes.rb
map.resource :api_key
You’ll need to allow the user to enable and disable the API, as well as re-generate their API key if they feel it’s been compromised. Add something like this to app/views/users/edit.html.erb:
<% if @user.api_is_enabled? %> <p> Your API Key: (<%= link_to "re-generate", api_key_path, :method => :post %> | <%= link_to "disable", api_key_path, :method => :delete %>) </p> <p> <strong><%= @user.api_key %></strong> </p> <% else %> <p> You'll need a unique key to make calls to the API. Remember to keep this key a secret as it can be used to access your account. </p> <p> <%= link_to("Get a key", api_key_path, :method => :post) %> </p> <% end %>
Authenticating the API Key
Add the following to lib/authenticated_system.rb:
def login_from_api_key self.current_user = User.find_by_api_key(params[:api_key]) unless params[:api_key].empty? end
Modify lib/authenticated_system.rb to add login_from_api_key as follows:
def current_user @current_user ||= (login_from_session || login_from_api_key || login_from_basic_auth || login_from_cookie) unless @current_user == false end
Optionally, if you’d also like to support access to the API via HTTP Basic Authentication using the API key in addition to a user’s login and password, you can make the following change to app/models/user.rb:
def self.authenticate(login, password) return nil if login.blank? || password.blank? if password.downcase == "x" # This is an API request u = find_by_api_key(login) else u = find_by_login(login.downcase) u && u.authenticated?(password) ? u : nil end end
When prompted to log in using HTTP Basic Authentication, use the API Key as the login and ‘X’ as the password.
Testing it Out
Assuming you have a RESTful resource called Items, you should be able to use curl as so:
curl http://www.yoursite.com/items/1.xml?api_key=356a192b
God Init.d Script for CentOS
This is the /etc/init.d/god script we are using for God on CentOS 5.
Get God
sudo gem install god
Create a Default Config File
sudo touch /etc/god.conf
Create the Init Script
Put this in /etc/init.d/god
#!/bin/bash # # God # # chkconfig: - 85 15 # description: start, stop, restart God # RETVAL=0 case "$1" in start) /usr/local/bin/god -P /var/run/god.pid -l /var/log/god.log /usr/local/bin/god load /etc/god.conf RETVAL=$? ;; stop) kill `cat /var/run/god.pid` RETVAL=$? ;; restart) kill `cat /var/run/god.pid` /usr/local/bin/god -P /var/run/god.pid -l /var/log/god.log /usr/local/bin/god load /etc/god.conf RETVAL=$? ;; status) RETVAL=$? ;; *) echo "Usage: god {start|stop|restart|status}" exit 1 ;; esac exit $RETVAL
Make it Executable
sudo chmod a+x /etc/init.d/god
Ensure God Launches on System Boot
sudo chkconfig --add god sudo chkconfig --level 345 god on
Fire it Up
sudo /etc/init.d/god start
Private, Authenticated RSS Feeds in Rails
So, you want to allow your users to access a RSS feed of private data in their account. Something like,
http://subdomain.yoursite.com/comments/123abc/feed.rss, where “123abc” is a secret token.
Here’s how to do this in Rails 2.1.2, though it will most likely work in other versions of Rails. In this example, each Account has_many Comments, and we’d like to get a RSS feed of comments.
1. Create a route for the feed in your routes.rb file.
map.resources :accounts do |account| account.comments_feed 'comments/:token/feed.:format', :controller => 'comments', :action => 'feed', :token => nil end
2. Create a new migration and add the feed_token to the Account.
class AddFeedTokenToAccount < ActiveRecord::Migration def self.up add_column :accounts, :feed_token, :string, :limit => 40, :default => "" end def self.down remove_column :accounts, :feed_token end end
3. When a new Account is created, create the feed_token. We’ll just use a standard SHA1 hash of the current time and the account id. This should be unique enough. Let’s also create a method to validate the feed token. All of this goes in app/models/account.rb
class Account < ActiveRecord::Base before_create :create_feed_token def valid_feed_token?(token) self.feed_token == token end protected def create_feed_token self.feed_token = Digest::SHA1.hexdigest(Time.now.to_s + self.id.to_s) end end
4. Add a new feed method to your Comments controller. This goes in app/controllers/comments_controller.rb
def feed @account = Account.find(params[account_id]) @comments = @account.comments @token = params[:token] respond_to do |format| if @account.valid_feed_token?(@token) format.rss { render :layout > false } else format.rss { render :nothing > true, :status > :forbidden } end end end
5. Create the file app/views/comments/feed.rss.builder. This is what generates the RSS feed.
xml.instruct! :xml, :version => "1.0"
xml.rss :version => "2.0" do
xml.channel do
xml.title "Comments"
xml.description "A bunch of comments"
xml.link account_comments_url(@account)
for comment in @comments
xml.item do
xml.title comment.title
xml.description comment.body
xml.pubDate comment.created_at.to_s(:rfc822)
xml.link account_comments_url(@account)
end
end
end
end6. Link to the comments RSS feed somewhere on your site. For example, somewhere in app/views/comments/index.html.erb place the following link:
<%= link_to 'Subscribe', account_comments_feed_path(@account, :format => :rss, :token => @account.feed_token)) %>
A Private Web Beta in Seconds with Prefinery
Don’t write it yourself
You’ve got some slick new Web site and you’d like to run a private beta. Maybe this is because you’re convinced your site is so awesome you’re going to get more traffic than your ready for. Or, maybe you’d just like to work out the bugs with a small, select group of users. Either way, you need a process for collecting the e-mail addresses for people who are interested in signing up, generating unique invitation codes, and sending an e-mail invitation.
This process is a pain in the ass, and not something core to your awesome new web site. Heck, you’ll probably only be in private beta for a few months so you’ll end up throwing away all the code you write to manage the private beta.
Prefinery can manage this entire process for you. Here’s how it works …
1. Sign up for a free Prefinery account
You specify what contact information (name, email, address, phone, etc.) must be gathered when users request an invitation code.
2. Install the invitation widget
This is as easy as copying and pasting a few lines of Javascript.
3. Users visit your web site and request an invitation code
The Prefinery invitation widget gets launched when a user clicks a link or image on your site. Your users never leave your web site!
4. Poof, an invitation code is generated
You log into Prefinery where you see the thousands of people who are begging to use your awesome new site. Approving access is as easy as clicking a button. Once access is approved, an e-mail (from your address, of course) is sent to the user.
5. Users sign up on your site
We give you the secret formula so that you can decode a Prefinery invitation code when users sign up on your site. We provide code samples in various languages, including Ruby, PHP, and Python. In most cases this process is as simple as one line of source code.
Learn more
You can learn more about Prefinery by taking the tour, checking out the screenshots, or signing up for a free account.
Backup Your WordPress Blog to Amazon S3 using Ruby
I’ve been running this blog for months without a backup solution. Mostly because I didn’t really care for any of the existing solutions which required me to do too many manual steps. I wanted something completely hands-off (automatically run every night), secure and reliable (store the backups on Amazon’s S3).
So, enjoy wordpress-s3-backup. Use it to backup your WordPress blog — both the database and the site. It’s a Ruby Rake script and you’ll need the AWS-S3 gem. Stick it in your crontab to run nightly and move on with your life.
How to Set an Expires Header in Apache
Setting an Expires (or Cache-Control) header in Apache will help speed up your Web site. We’re running Apache 2.x, and define an expires header for all of our static assets (images, stylesheets, and scripts).
Just add the following to your <VirtualHost> section of your Apache configuration:
ExpiresActive On
ExpiresByType image/png “now plus 365 days”
ExpiresByType image/jpeg “now plus 365 days”
ExpiresByType image/gif “now plus 365 days”
ExpiresByType application/javascript “now plus 365 days”
ExpiresByType application/x-javascript “now plus 365 days”
ExpiresByType text/javascript “now plus 365 days”
ExpiresByType text/css “now plus 365 days”
You can read all about expires headers by reading Yahoo!’s Best Practices for Speeding Up Your Website guide.
Also, be sure to check out our post on how to speed up your Website by Configuring Apache to Gzip Your Components.
How to Configure Apache to Gzip Your Components
Compressing your Web components will help speed up your Website. The majority of your visitors will benefit as most all Web browsers support gzip compression. You’ll want to compress all text, which includes html, css, javascript, xml, json, etc.
Apache 2.x uses mod_deflate, and all you need to do is add the following to your <VirtualHost> section of your Apache configuration:
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
All you truly need is the first line. The BrowserMatch lines are there to handle issues with old browsers.
You can read all about gzipping by reading Yahoo!’s Best Practices for Speeding Up Your Website guide.
Also, be sure to check out our post on How to Set an Expires Header in Apache, which will also help speed up your Website.
Announcing Major Enhancements for Prefinery
Some major enhancements are coming to Prefinery on December 10, 2008. Here’s the complete run-down:
Personalized subdomains
Every company account gets a free, personalized subdomain. In addition to giving you the opportunity to add a bit of branding to the URL, you will now log in to administer your betas using this new subdomain. For example, if your subdomain is “adobe” you will now log in at http://adobe.prefinery.com/admin
Separate administrator and tester areas
As an administrator of a beta program, you will log into Prefinery using your personalized subdomain (e.g., http://adobe.prefinery.com/admin) and will interact with a management console. Testers will access your beta at a separate location and view a unique set of pages that you have customized.
Complete user interface redesign
The first thing you’ll notice when you log in is that Prefinery has received a major facelift. We’re not talking a nip here and a tuck there. We mean Prefinery fled to a country without extradition and got a brand new identity.
Landing / Welcome page
Create a custom landing page for your testers using our easy to use Web page editor. You don’t need to know any HTML to create a beautiful welcome page. We’ll add generic log in and join links to the page, but the rest of the content is up to you.
Improved custom branding
When you subscribe to a plan with custom branding, you’ll be getting a blank slate. You’ll have complete control over the content and styling of the page so that you may provide your testers with a familiar experience. In fact, once you add your logo to the page, testers may not even realize they’re not on your site.
Guestbook creation
Specify what contact information is required to be gathered from testers when they join your beta. Pick from email address, name, address, employer, job title, and telephone.
Require a survey to join
Require testers to take one of your surveys prior to joining your beta. Perfect if you want to collect more information than the guestbook supports. Also a great way to attach a sign up application to your beta.
Require a survey to download files
Require testers to take one of your surveys prior to downloading a specific file. Perhaps anyone can download version 1.0, but you want to require the survey “1.0 Feedback” prior to downloading version 2.0.
Sexy survey results
We’re using a whole new package for our graphs and charts. They’re faster, interactive, and look great when sporting your data.
Bugs, comments consolidated
We’ve combined bugs and comments. Prefinery is not competing in the bug tracking and ticket management space. Plenty of excellent tools already exist. So, we’ve merged bugs and comments since both are nothing more than tester feedback. You’ll still be able to export the data.
Plus, dozens of tiny improvements
We hope you enjoy these additions and enhancements. We’d love to hear your feedback!
About Justin
Search
Recent Posts
- A Simple Formula for Evaluating Risk
- Not Having a Plan B Makes Plan A More Successful
- Easy Rails API Authentication Using restful-authentication
- God Init.d Script for CentOS
- Private, Authenticated RSS Feeds in Rails
- A Private Web Beta in Seconds with Prefinery
- Backup Your WordPress Blog to Amazon S3 using Ruby
- How to Set an Expires Header in Apache


