How to create a twitter section
Here's an example of how to create a section that will read tweets from a specified user. After you've created the section you can put it anywhere on your website to show your latest Twitter updates. The tweets will be cached into a yaml file to minimize requests and just in case Twitter is unavailable.
So let's get started. First create the following folder structure and files.
The files
Root
|-app
|-models
|sections
twitter_section.rb
|-templates
|-sections
|-twitter_section
|-default
index.html.erb
|-views
|-skyline
|-sections
_twitter_section.html.erb
The migration
A section is a subclass of Activerecord::Base so we'll need to create a migration for it.
$ ./script/generate migration CreateSectionsTwitterSection
For this example the only variable field of the section is the user, but you could also use it to set the maximum amount of tweets you want to show.
class CreateSectionsTwitterSection < ActiveRecord::Migration
def self.up
create_table :sections_twitter_sections do |t|
t.string :user
t.timestamps
end
end
def self.down
drop_table :sections_twitter_sections
end
end
The model
All the sweetness of our Twitter section will go into the model. This is where we will read the tweets, write them into a yaml file and make them available.
It's pretty self explanatory. The tweets method makes a call to fetch_tweets which checks if there are cached tweets. If there's no cache or if the cache has timed out it will connect to Twitter to get the new tweets.
Of course if it can't connect and there is an old cache file, it will just use that one.
- Twitter API
-
Checkout the twitter API on: http://apiwiki.twitter.com/ to get comfortable with all the possibilities of Twitter.
For this example we've just used statusses/timeline.json to display the timeline of a user, but there's a lot more you can do.
So here's the code for the model
require 'open-uri'
require 'fileutils'
class Sections::TwitterSection < ActiveRecord::Base
set_table_name :sections_twitter_sections
extend ActiveSupport::Memoizable
include Skyline::Sections::Interface
cattr_accessor :cache_path
@@cache_path ||= Skyline::Configuration.twitter_section_cache_path
cattr_accessor :cache_timeout
@@cache_timeout ||= Skyline::Configuration.twitter_section_cache_timeout
after_update :delete_from_cache
after_destroy :delete_from_cache
def tweets
self.fetch_tweets
end
protected
def cache_file
File.join(self.class.cache_path, "#{self.id}.yml")
end
memoize :cache_file
def fetch_tweets
if File.exists?(self.cache_file) && File.mtime(self.cache_file) > Time.now - self.cache_timeout
tweets = YAML.load(File.read(self.cache_file))
else
if tweets = get_tweets_from_twitter
cache(tweets)
tweets.collect!{|t| t['user']['screen_name'] + " tweeted " + t['text']}
elsif File.exists?(self.cache_file)
self.reset_mtime
YAML.load(File.read(self.cache_file))
else
false
end
end
tweets
end
memoize :fetch_tweets
def url
"http://twitter.com/statuses/user_timeline.json?screen_name=#{self.user}"
end
def get_tweets_from_twitter
feed = ::ActiveSupport::JSON.decode open(self.url).read
rescue
logger.error "[TwitterSection] Failed to fetch!"
false
end
def cache(feed)
File.open(self.cache_file, "w") do |f|
f.write feed.to_yaml
end
end
def reset_mtime
FileUtils.touch(self.cache_file)
rescue
end
def delete_from_cache
File.delete(self.cache_file)
rescue
end
end
The template
There's not much going on in the template here. As a title I've put in the user that we're diplaying the tweets from and I've chosen to only show the 5 last tweets.
The json object comes back with loads of fields, for this example I'm only interrested in the text field, hence the t['text']. I've used the auto_link helper to let rails create links if there are any.
Now it's up to you to make some fancy css to go with the section.
<dl class="info">
<dt><%=twitter_section.user%></dt>
<dd>
<% if twitter_section.tweets.present? %>
<div class="text">
<% twitter_section.tweets.each_with_index do |t,i| %>
<% if i < 5 %>
<p><%= auto_link(t["text"].to_s) %></p>
<% end %>
<% end %>
</div>
<% end %>
</dd>
</dl>
The view
The section will also need a form to set the username when we add it to a page. SkylineCMS renders a partial with the section name from views/skyline/sections
The form definition is all doen by skylineCMS so we only need to add the fields.
<table class="fields">
<tr>
<th><%=sectionable_form.label_with_text :user %></th>
<td><%=sectionable_form.text_field :user %></td>
</tr>
</table>
The configuration
The only thing left is adding the following lines to your skyline_configuration.rb in config/initializers.rb
This sets your cache path and timeout and adds your new TwitterSection to your sections.
config.twitter_section_cache_path = File.join(Rails.root,"tmp/cache/twitter_sections/cache")
config.twitter_section_cache_timeout = 15.minutes
config.sections[:default] += [Sections::TwitterSection]