Sinatra To Do List in 60 Lines of Code

One of the nice things about Sinatra is you can build apps in any way you want and you only need one file.

I’ve been playing around over the weekend and managed to build a very simple To Do list app, very similar to SuperDo. But it only uses one file and exactly 60 lines of code - including views!

It works like a charm, using a REST api to create, update and delete tasks. Completed tasks are crossed out and blank tasks aren’t allowed (although there’s no error message). Oh, and it also uses HTML5, so it must be super cool!

I don’t think I can make this any shorter - anybody got any suggestions?

require 'sinatra'
require 'data_mapper'
DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/development.db")
class Task
  include DataMapper::Resource
  property :id,           Serial
  property :name,         String, :required => true
  property :completed_at, DateTime
end
get '/' do
  @tasks = Task.all
  haml :index, :format => :html5
end
post '/' do
  Task.create(:name => params[:name])
  redirect '/'   
end
get '/:id' do
  @task = Task.get(params[:id])
  haml :edit, :format => :html5
end
put '/:id' do
  task = Task.get(params[:id])
  task.completed_at = params[:completed] ?  Time.now : nil
  task.name = (params[:name])
  task.save ? (redirect '/') : (redirect '/' + task.id.to_s)
end
delete '/:id' do
  Task.get(params[:id]).destroy
  redirect '/' 
end
DataMapper.auto_upgrade!
__END__
@@ layout
!!! 5
%html
  %head
    %meta(charset="utf-8")
    %title To Do List
    %style li.completed{text-decoration:line-through;}    
  %body
    %h1 <a title="Show Tasks" href="/">To Do List</a>
    = yield
@@ index
%form(action="/" method="POST")
  %input#name(type="text" name="name")
  %input(type="submit" value="Add Task!")
%ul#tasks
  -@tasks.each do |task|
    %li{:class => (task.completed_at ? "completed":  nil)}
      %a(href="/#{task.id}")= task.name
@@ edit
%form(action="#{@task.id}" method="POST")
  %input(name="_method" type="hidden" value="PUT")
  %input#name(type="text" name="name"value="#{@task.name}")
  %input#completed{:name => "completed",:type => "checkbox",:value => "done",:checked => (@task.completed_at ? "checked":  nil)}
  %input(name="commit" type="submit" value="Update")
%form(action="#{@task.id}" method="POST")
  %input(name="_method" type="hidden" value="DELETE")
  %input(type="submit" value="Delete") or <a href="/">Cancel</a>
blog comments powered by Disqus