Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
require 'rubygems'
require 'sinatra'
require 'redis'
# To use, simply start your Redis server and boot this
# example app with:
# ruby example_note_keeping_app.rb
# Point your browser to http://localhost:4567 and enjoy!
# Create the Redis client when the script starts
$redis =
helpers do
def tag_link(t, title = nil)
arr = t.is_a?(Array) ? t : (@current_tags || []).dup.push(t)
path = arr.uniq.join('/')
%!<a href="/tags/#{path}">#{title || t}</a>!
# Loads all notes given by an array of IDs in a single Redis call
def load_notes(ids)
if ids.empty?
$redis.mget(* { |id| "note-#{id}" }).map { |raw| Marshal.load(raw) }
get '/' do
@notes = load_notes $redis.smembers("all-notes")
erb :index
get '/tags/*' do
@current_tags = params[:splat].first.split('/')
redirect '/' if @current_tags.empty?
# Names of the tag-sets
sets = { |t| "tag-#{t}" }
# Load all notes that reside in the intersection of these sets
@notes = load_notes $redis.sinter(*sets)
erb :index
get '/new' do
erb :new
post '/new' do
# Extract tags from request parameters
tags = params[:tags].gsub(/\s+/, '').split(',')
# Get ID for the new note
note_id = $redis.incr(:note_counter)
# Store the note
$redis.set("note-#{note_id}", Marshal.dump({ :contents => params[:contents], :tags => tags }))
$redis.sadd("all-notes", note_id)
# Add the ID to the tag-sets
tags.each { |t| $redis.sadd("tag-#{t}", note_id) }
redirect '/'
@@ layout
<title>My notes</title>
<style type="text/css" media="screen">
#main {
font-family: Helvetica;
width: 400px;
margin: 60px auto;
#head div {
float: right;
text-align: right;
font-size: 0.8em;
a {
text-decoration: none;
color: #000;
label {
font-size: 0.8em;
display: block;
width: 70px;
legend {
font-weight: bold;
input, textarea {
width: 100%;
margin-bottom: 1em;
input.submit {
width: auto;
float: right;
font-weight: bold;
div.note {
border-top: 2px dashed #bbb;
padding: 0.3em 1em;
background-color: #FFFFA0;
margin-bottom: 1em;
div.note .tags {
font-size: 0.6em;
font-style: italic;
color: #333;
div.note .tags > a {
color: #333;
h3.tags a span {
color: #f00;
font-size: 0.8em;
<div id="main">
<div id="head">
<a href="/new">new note</a>
<h1>My notes</h1>
<%= yield %>
@@ new
<legend>New note</legend>
<form action="/new" method="post">
<textarea name="contents"></textarea>
<input type="text" name="tags" />
<input type="submit" value="Save" class="submit" />
@@ index
<% unless @current_tags.nil? %>
<h3 class="tags">
Notes tagged with:
<%= do |t|
t + tag_link(@current_tags - [t], "<span>(x)</span>")
end.join(', ') %>
<% end %>
<% @notes.each do |note| %>
<div class="note">
<div class="tags">
Tags: <%= note[:tags].map { |tag| tag_link(tag) }.join(', ') %>
<pre><%= note[:contents] %></pre>
<% end %>

This comment has been minimized.

Copy link

@yeban yeban commented Feb 8, 2011

I get an error when I have no notes: "wrong number of arguments to mget". Adding the following to load_notes (line 24) fixes it:

return [] if ids.empty?


This comment has been minimized.

Copy link
Owner Author

@pietern pietern commented Feb 8, 2011

Thanks, fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment