This is a short tutorial on how to deploy an Sinatra web app that uses Superfeedr to Heroku. This app provides a very simple home page that lists the latests entries of some of your favorites sites. It’s greatly inspired by the awesome start.io from the awesome Peter Vidani and Jacob Bijani
Set up
We will use Sinatra, the Rack Superfeedr gem, as well as Twitter’s bootstrap for the layout, because I suck at making things shinny.
Let’s start first by creating the application on Heroku.
Create the repo:
mkdir start-page && cd start-page
git init
git add .
git commit -m "init"
Create the application on Heroku:
heroku create —stack cedar
Add the hostname as an environment variable. It is used by the rack middleware to build the callback urls:
heroku config:add HOST=<YOUR APP DOMAIN>
Add the superfeedr addon:
heroku addons:add superfeedr
Implementation
This implementation is minimalistic, feel free to look at the code closely.
Let’s add the files:
touch app.rb
touch config.ru
touch Gemfile
mkdir views/ && touch views/index.erb
In app.rb
:
require 'sinatra'
require 'rack-superfeedr'
require 'cgi'
configure do
# Application settings
set :host, ENV['HOST']
set :login, ENV['SUPERFEEDR_LOGIN']
set :password, ENV['SUPERFEEDR_PASSWORD']
# List all the feeds you want to subscribe to below.
set :feeds, [
'http://blog.superfeedr.com/atom.xml',
'https://github.com/superfeedr',
'http://feeds.feedburner.com/avc',
'http://push-pub.appspot.com/feed'
]
# The datastore... (volatile for this application)
set :stories, {}
end
# We use JSON for the data format
use(Rack::Superfeedr, { :host => settings.host, :login => settings.login, :password => settings.password, :format => 'json', :async => true }) do |superfeedr|
superfeedr.on_notification do |notification|
notification['items'].each do |item|
settings.stories[CGI::escape(item['id'])] = item # keeping the story
end
end
# Subscribing to all the feeds we want.
# Subscriptions are stateful, so we could avoid resubscribing them everytime we boot the application,
# but we want to keep this application stateless for demo purposes
settings.feeds.each do |url|
superfeedr.subscribe(url)
end
end
# Home page
get '/' do
erb :index
end
# Redirects. Important for marking the stories as read!
get '/read/:id' do
if params[:id] && entry = settings.stories[params[:id]]
settings.stories.delete(params[:id])
if url = entry['permalinkUrl']
redirect to(entry['permalinkUrl'])
end
else
halt 404
end
end
In config.ru
:
require './app'
run Sinatra::Application
In Gemfile
:
source 'http://rubygems.org'
gem 'sinatra'
gem 'rack-superfeedr'
In views/index.erb
:
<!DOCTYPE html>
<html>
<head>
<title>Start Page</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="http://twitter.github.com/bootstrap/1.4.0/bootstrap-dropdown.js"></script>
<script src="http://twitter.github.com/bootstrap/1.4.0/bootstrap-alerts.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css">
</head>
<body style="padding-top: 50px;">
<section id="navigation">
<div class="topbar-wrapper" style="z-index: 5;">
<div class="topbar" data-dropdown="dropdown">
<div class="topbar-inner">
<div class="container">
<h3><a href="/">Start Page</a></h3>
<ul class="nav">
</ul>
</div>
</div><!-- /topbar-inner -->
</div><!-- /topbar -->
</div><!-- /topbar-wrapper -->
</section>
<div class="container">
<% index = 0 %>
<% settings.stories.each do |id, story| %>
<% if (index % 3) == 0 %>
<div class="row">
<% end %>
<div class="span5">
<h2><%= story["title"] %></h2>
<p><%= (story["summary"].nil? || story["summary"] == "" ? story["content"] : story["content"]).gsub(/<\/?[^>]*>/, "")[0..280] %></p>
<p><a class="btn" href="/read/<%= CGI::escape(id) %>" target="_blank">Read »</a></p>
</div>
<% if (index % 3) == 2 %>
</div>
<% end %>
<% index += 1 %>
<% end %>
</div>
</body>
</html>
Let’s commit all files.
git add .
git commit -m "implemented" -a
Deploying
That’s the simplest part:
First, let’s install the gems.
bundle install
git add Gemfile.lock
git commit -m "adding Gemfile.lock" -a
And push the code
git push heroku master
… And that’s it!
Point your browser to your Heroku application. It is likely that you’ll have to wait for the feeds you have added to have new content before you see it appear on your home page. The last step is to make this page your default start page in your favorite web browser.
Gotchas
Heroku will put this application to sleep if you only use a single dyno… and since we store the entries in memory for now, that means you’ll lose that data if the app goes idle. The solution is very simple: store the data, using another Heroku addon!
Of course, this is a very simple application and there is a ton of little things that one can do to improve it:
- add the ability to dynamically subscribe to feeds
- show meta data, like the number of bit.ly clicks on each of the stories
- auto-refresh the page
- …
The Superfeedr Heroku addon is still in alpha to this date, so if you want to run, this, please email us and we’ll get you in!
Comments