Kelli Shaver

Month

March 2012

17 posts

Bash Script to set up Sinatra App → gist.github.com

Last week, I talked about how I structure my Sinatra apps. Today I decided to automate that process, so here’s a small shell script to auto-generate the directory structure and a few essential base files.

Mar 30, 2012
#bash #sinatra #ruby #work #automation #dev
Mar 27, 2012
#home #floor!
Structuring Sinatra Applications

I thought it might be interesting to show how I structure my Sinatra applications. The app shown below (itemize.cc) is fairly small, so some of this may be a bit overkill, but I decided to go ahead and go with this level of structure, so I could easily expand the app in the future without having to worry about things getting disorganized.

Things of note:

The app.yml file is a config file that stores app-specific config items. For instance, in this case, it has the db connection string, wkhtmltopdf path, whether or not to run migrations on start up, and SMTP server details.

Inside the main app, I typically pull in files by directory, so dropping in new files is painless.

Often, I’ll also include a lang directory, with language files (e.g. en-us.rb) and then set the default language in app.yml as well.

You can see it all come together like so:

require 'rubygems'
require 'sinatra'

configure do
  @@config = YAML.load_file("./app.yml") rescue nil || {}
end

Dir["./helpers/*.rb"].each {|file| require file}

DataMapper.setup(:default, ENV['DATABASE_URL'] || @@config["db_connection_string"])
DataMapper::Property::String.length(255)

Dir["./models/*.rb"].each {|file| require file} 
DataMapper.finalize 

if @@config["db_run_migrations"] == true 
  DataMapper.auto_migrate! 
  DataMapper.auto_upgrade! 
end

not_found do 
    erb :not_found 
end 

error do 
  erb :error 
end 

get '/' do 
  erb :index 
end 

Dir["./routes/*.rb"].each {|file| require file}
Mar 23, 2012
#dev #sinatra
Re-Thinking The Way I Use Git

Let me preface this by saying that I am probably late to the party on this one.

I’ve been using Git as my VCS for a long time, and I love it, but I have to admit, I’ve been pretty disorganized in the way in which i use it. My Git workflow has been basically this:

Do some work, get to a point where things work, make a commit, push.

I’d make the occasional branch if was doing something radically different, like a big rewrite, or refactoring, throw in an occasional rebase or filter-branch, sure, but that was basically how it went.

For most of the work I do, I am the only developer involved, or there may be one other person reviewing the code and making small commits. So this method has worked OK, in that let me do things like roll back to an earlier commit when I would screw something up.

However, it never felt like I was utilizing Git to its fullest potential, and I’d never really thought about Git as a tool for documenting the development life-cycle of my code. That is, not until a few days ago when a good friend introduced me to Git-flow.

Git-flow is both a methodology and a set of command-line tools to put that methodology into practice. In a nutshell, you work off of a development branch, creating hotfixes, support code, and features that follow a standard naming convention, and then get merged into the development branch. From there, you create releases, which them merge with the master, once you’ve done all of your testing and tidying up. So your master branch never has anything other than stable release code merged into it and your development branch has a full history of all changes, all properly categorized.

I’ve only been at this a few days, but i absolutely love it. It takes a bit of getting used to, but I love the history that it creates, the built-in safety net, and the structure it imposes on the code. I’m still adjusting, but I think it’s definitely been a worthwhile switch that will save a lot of headache in the future, especially when multiple developers are involved.

Mar 22, 20121 note
#git #git-flow #dev #code #work
Simple Invoicing for Small Jobs

Say Hello to Itemize.cc

I’ve been working on a little personal project and yesterday I put it up on the web for all to see (and this morning i found and fixed a fatal bug….. go figure). So here it is: Itemize.cc

It’s a very simple invoicing tool. It lets you quickly create and share invoices with your clients, and gives them a big, friendly button that they can click to pay your invoice through PayPal. It also gives them, and you, an option to download the invoice as a PDF file.

That’s about it. There’s no sign-up or registration required. It’s just very basic, simple invoicing.

I still need to do some work on it, optimization for mobile, that kind of thing, so consider this a beta release.

Itemize was built with Sinatra.

Mar 22, 20121 note
#dev #itemize #web apps #business
Want web accessibility? Don't forget about print styles. → stephaniehobson.ca

I’ll admit to being guilty of forgetting about the print styles, myself, when it comes to my own stuff, or at least of having had it fall into the category of “haven’t gotten around to it yet.”

Mar 19, 2012
#design #web #accessibility
Mar 17, 20122 notes
#random #photography
Mar 16, 20121 note
#macbok air #apple
Your Users Are Not Users

A while back, we made an unofficial company policy, if you will, to stop referring to the people who used our applications as users. We stopped calling them that on the web sites, in the documentation, and even in the code.

We started calling them people, instead, because that’s what they are. The term “users” made it sound like we cater to a bunch of junkies or ingrates. We don’t. We build apps for people.

It sounds like such a small thing, but over time, it really shapes your perspective, which can have a big impact on the way you think about your UX. You’re no longer developing for some generic ‘User’ object, you’re creating an experience for a real, live person.

People and users have different needs. Users require instruction and access to a presentation layer that allows them to do stuff. A person needs to understand, needs to feel important, needs empathy, has to pick the kid up from soccer practice at 4, hold their phone in one hand and the baby in the other, and so on.

Person carries with it a degree of respect and responsibility that User does not.

Mar 16, 2012
#work #dev #code #philosophy
Mar 15, 2012
#work #random
Mar 14, 2012
#design #accessibility #basecamp
Static Splash Pages in Wordpress

I’m generally not a big fan of splash pages. I think they do little more than to create another barrier of entry and make more work for the person visiting your site. These once-common, but thankfully less-frequently occurring pages still have their occasional uses, though.

Recently, I was working on a site for a client who was running a big promotion and they really wanted to advertise it with a splash page on their site, which is powered by Wordpress. After some discussion about what would be the most effective and least painful for their visitors, we decided on a splash page that would appear no more than once a day, no matter hwo many times the visitor went to the site. The visitor would be able to click through the splash page, and it would display for no more than 20 seconds (long enough to read it) if they didn’t.

At first, this seemed simple. I would just add ‘index.html’ to the DirectoryIndex directive in their .htaccess file and upload a static HTML file for the splash page, with a JavaScript redirect.

However, that doesn’t exactly work - Wordpress’ own rewrite scripts will send you into an infiniate loop of redirects if you go this route.

So here’s my simple solution. Go to your currently active theme and open the header.php file. You’re going to build your splash page inside there.

Place your splash page HTML at the very top of this file, wrapped in a couple of conditonal statements that make sure the page isn’t being accessed via an internal link, and that check for the existence of the ‘seen’ cookie.

<?php if ((strpos($_SERVER['HTTP_REFERER'], get_bloginfo('home')) === false)
     && !$_SERVER['QUERY_STRING'] && !isset($_COOKIE['seen'])): ?>

<!DOCTYPE html>
<head>
<title>Your Site</title>
</head>
<body>
    <a href="index.php">Continue to main site...</a>
    <script type="text/javascript">
        var days = 1 // change this to make the cookie last longer than 24hrs
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
        document.cookie = "seen=true"+expires+"; path=/";
        setTimeout(function() {
            window.location.href="/";
        }, 20000);
    </script>
</body>
</html>

<?php
exit;
endif;
?>

There you go. that’s all there is to it.

Note the JavaScript in the splash page, it’s very important. We set a cookie called ‘seen’ with a value of true whenever the page is visited, then we redirect to the website root after 20 seconds. Without this, your visitors will see the splash page every time they return to the website.

Mar 13, 2012
#php #javascript #wordpress
Responsinator → responsinator.com

Quickly test responsive designs at multiple device resolutions.

I love a good -inator.

Mar 13, 2012
#design #mobile #responsive web
My big takeaway from the iPad 3 announcement...

…is that Tim Cook needs to stop trying to give Steve Jobs presentations and find his own voice. Mr. Cook is a very sharp, smart guy, but yesterday’s presentation felt very forced and like a bad impersonation. Phill Schiller’s presentation was much better.

For many years, Jobs’ voice was Apple’s voice, and changing that can certainly have a big impact on your brand, but poorly executing it is, I think, even worse.

Jobs’ death was tragic, and regardless of your feelings about him, or Apple, there’s no denying that it had a huge impact on a lot of people who need and want time to mourn that loss, and that’s fine, but at some point you have to embrace the change in leadership for its new potentials and possibilities.

So no more strained, Steve Jobs-esque presentations, please. Let’s get to know Tim Cook.

Mar 8, 2012
#apple #steve jobs #tim cook
Sinatra Producton Server Setup

I recently had to set up a couple of web servers to handle multiple Sinatra applications in production. Going from a fresh install of the operating system (Ubuntu in this case) to fully working server, with Nginx, Passenger, Ruby, and Git-based deployment is a bit of a lengthy process, so I thought I’d take a few moments to outline the steps I took below.

A Couple of Notes:

  1. I was setting up some very lightweight applications, which didn’t use a database, so there are no database installation instructions outlined below, and the default configs for Passenger, Nginx, etc. as far as memory usage, pool sizes, and so on, were fine. If you’re deploying beefier applications, you will need to allocate resources accordingly.
  2. My server environment, in this case, was Ubuntu on an EC2 instance. All firewall configuration was done beforehand from the EC2 console. If you’re setting up on a different VPS provider, you’ll need to manually configure your firewall via iptables.

Now, on to the good bits. We’ll be jumping back and forth between our local machine and the remove server a bit, so let’s start things off….

On the SERVER

Update the OS

sudo apt-get update sudo apt-get upgrade

Set the Hostname

sudo nano /etc/hostname

Install Utilities

sudo apt-get install wget build-essential 

Install & Configure Git

sudo apt-get install git-core 
git config --global user.name = "<name>"
git congit --global user.email = "<email>"

Install & Configure Gitosis

git clone git://eagain.net/gitosis.git 
cd gitosis
sudo apt-get install python-setuptools
sudo python setup.py install
sudo adduser --system --shell /bin/sh --gecos 'git version control' --group --disabled-password --home /home/git git

Copy your SSH keypair to ~/.ssh then set permissions, initialize Gitosis and ensure proper permissions on update hooks.

chmod 0600 ~/.ssh/id_rsa 
sudo -H -u git gitosis-init < ~/.ssh/id_rsa.pub
sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

To avoid pesky ownership permissions, let’s just add Git to the sudoers file so that we can run our post-update hooks without issue. If you’re super concerned about security, you can skip this step and and just make Git the owner of each application root directory.

sudo visudo git ALL=(ALL) NOPASSWD:ALL

Install RVM

sudo bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer) 
umask g+w
source /etc/profile.d/rvm.sh
sudo apt-get install openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion

Now give your user permissions to do stuff in RVM.

sudo chown -R [user]:[user] /usr/local/rvm

Install Ruby & RubyGems

rvm install 1.9.2 
source "/usr/local/rvm/scripts/rvm"
rvm --default use 1.9.2

Install Gems

gem install rack rake sinatra thin bundler

Install Nginx & Mod Rails

sudo apt-get install libcurl4-openssl-dev libssl-dev zlib1g-dev gem install passenger 
rvmsudo passenger-install-nginx-module

Select the first option and set install dir to /etc/nginx (purely personal preference, but it feels more consistent than having it in /opt)

Install Nginx Control Script

cd /opt 
sudo wget -O init-deb.sh http://library.linode.com/assets/604-init-deb.sh
mv /opt/init-deb.sh /etc/init.d/nginx
chmod +x /etc/init.d/nginx
/usr/sbin/update-rc.d -f nginx defaults

Since we changed the install directory, we have to edit the control scripts.

sudo nano /etc/init.d/nginx

edit PATH and DAEMON to point to the right location

Make some directories

cd /srv 
sudo mkdir www
sudo mkdir
www-logs
sudo mkdir www/<project>
sudo chmod -R 0777 www
sudo chmod -R 0777 www-logs

Set up Nginx Virtual Hosts

sudo nano /etc/nginx/conf/nginx.conf

Below is a sample nginx.conf file:

worker_processes 1;
events {
worker_connections 1024;
}

http {
passenger_root /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11;
passenger_ruby /usr/local/rvm/wrappers/ruby-1.9.2-p290/ruby;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name www.<project> <project>;
access_log /srv/www-logs/<project>.access.log;
error_log /srv/www-logs/<project>.error.log;

root /srv/www/<project>/public;
passenger_enabled on;

location /static {
root /srv/www/<project>/public;
index index.html;
}
}
}

Set up Gitosis Hosting for Repos

cd ~ 
git clone git@<server>:gitosis-admin.git
cd gitosis-admin
nano gitosis.conf

Below is a sample gitosis.conf setup:

[group <company>]
writable = <project>
members = <user>

Then commit it.

git add .
git commit -a -m "adding <project> repos"
git push

Go to your LOCAL repos!

Add remotes to repos and Push

cd ~/www/<project> 
git remote add production git@<server>:<project>.git
git push production master

Back to the SERVER!

Set up Deploy Hooks

sudo nano /home/git/repositories/<project>.git/hooks/post-update

Below is a sample post-update script:

#!/bin/sh 
git archive --format=tar HEAD | (cd /srv/www/<project>/ && tar xf -) sudo touch /srv/www/<project>/tmp/restart.txt

Make it executable.

sudo chmod 0755 /home/git/repositories/<project>.git/hooks/post-update

And now back to the LOCAL repos!

Deploy Stuff

cd ~/www/<project> 
mkdir tmp
touch tmp/restart.txt
git add .
git commit -a -m "adding restart.txt for passenger"
git push production

Back to the SERVER!

Restart Nginx

sudo /etc/init.d/nginx restart

And that should be it. You should now be good to go.

Mar 6, 20125 notes
#ruby #linux #ubuntu #server #passenter #mod rails #nginx #sinatra #git #sysadmin
Not Sure Where I Stand on This

Every time I use a weakly typed language: “I wish this language had strong typing.”

Every time I use a strongly typed language: “I wish this language had weak typing.”

Mar 5, 2012
#code #random
Document Your APIs with Happy Docs

Things are getting busy at work. We’re rolling out several new apps for web and various mobile platforms. Nearly each of these apps has an accompanying REST API, but each is very different. Documentation was starting to get a bit fragmented and tedious.

So I spent a few hours last week/this weekend building Happy Docs, a lightweight CMS for creating HTML documentation for REST APIs (Get it? HTML+API+docs=Happy Docs) and I have been given the OK to open source it.

The current feature set is very MVP with a few small bonuses, like the ability to have private (password-protected) projects, exporting to PDF, and rudimentary theme support on the public docs. the admin UI also still needs some clean-up, I feel, but it’s all perfectly functional and I like where it’s heading.

So if you’re building APIs and looking for a good way to document them, check it out. We think it’s pretty nifty.

(Happy Docs was built in CodeIgniter runs on PHP5.3+ and requires MySQL and wkhtmltopdf)

Mar 5, 2012
#API #HappyDocs #CodeIgniter #open source
Next page →
2012 2013
  • January 5
  • February 4
  • March 3
  • April 3
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December
2012 2013
  • January 9
  • February 18
  • March 17
  • April 7
  • May 9
  • June 9
  • July 14
  • August 14
  • September 2
  • October 8
  • November 7
  • December 8