Twitter Gem Examples
APR
22
2009
I recently set up a Twitter account for a monthly bill and task tracking application that I built a few months back. My intent was to try and drive traffic to my site (which had been sitting unused by the general public). To do this, I decided to mass-follow around 350 accounts in hopes of having them follow me back and checking out the site. It worked pretty well, and I even had quite a few users cold follow the account. At first, I would follow the users that followed me when I got the notification from Twitter. After a few days, I got a little behind and the followers started to build up. I figured this would be a good time to check out the Twitter gem to see if I could automate some of my tasks. The gem had exactly what I needed: a way to talk to Twitter via Ruby. I've included below two of the tasks that I created to work with my Twitter account.
First things first, I needed to set up my authentication. To do this, I just created a YAML file in my home directory called .twitter that contains my user email and password. The . means that it's a hidden file (I'm on a Mac). The YAML file is extremely simple, and looks like this:
email: my_twitter_email password: my_twitter_password
Now, I could use this YAML file for any of the scripts that I wrote.
Task #1: Follow Users Who Follow Me
I wanted to get a list of all my followers and check to see if I'm already following them. If I'm not, I want to create a friendship with them.
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'
config = YAML::load(open("#{ENV['HOME']}/.twitter"))
httpauth = Twitter::HTTPAuth.new(config['email'], config['password'])
base = Twitter::Base.new(httpauth)
base.followers.each do |follower|
if !follower.following
# make sure to rescue in case there is anything wrong with the account
base.friendship_create(follower.id, true) rescue next
puts "Created friendship with #{follower.screen_name}"
end
end
Task #2: Stop Following Users Who Aren't Following Me
I followed about 350 accounts initially, and after about a week, I figured that if they weren't following me by then, they'd probably never follow me. So, since I'm all about reciprocation, I decided to stop following them.
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'
config = YAML::load(open("#{ENV['HOME']}/.twitter"))
httpauth = Twitter::HTTPAuth.new(config['email'], config['password'])
base = Twitter::Base.new(httpauth)
base.friends.each do |friend|
if !base.friendship_exists?(friend.screen_name, 'listode')
base.friendship_destroy(friend.id)
puts "Destroyed friendship with #{friend.screen_name}"
end
end
A Quick Note
Keep in mind that, unless you've been white-listed, your account is limited to 100 API calls per hour. That shouldn't be an issue with the first script, since it only makes one call to get the list and one call for each friend creation. You should stay below the cap (unless you have more than 100 followers who you aren't following).
The second script is a different story. It makes one call to get the list of friends, one call for each friend to check following, and one call to destroy the friendship if they aren't following. This can easily burn up the API limit if you have more than 100 friends. I haven't figured out a way to reduce the number of API calls for that script. If you have any tips, leave them in the comments.
Better Text Replacement with CSS
APR
16
2009
There are several methods for rendering non-web fonts (eg. Cufón and sIFR). Both are tedious to set up and implement. The easiest alternative is the good old image-instead-of-text trick, but that's not good for SEO, even with alt tags.
There is a way to have SEO text AND use an image as the text. With a little CSS trickery, you can easily achieve the desired effect. Worth noting, however, is that this method is really only good for non-dynamic, fixed width text (such as headings). It's not practical for blocks of text.
The first thing you need is an image for the text you want to replace (and yes, I'm using Comic Sans):
Now for the html code that we'll be working with:
<h1 class="replace heading">My Heading</h1>
The CSS does all the work.
.replace {
display:block;
height:0;
overflow:hidden;
font-size:0;
letter-spacing:-1em;
text-indent:-1000em;
}
.heading {
width:135px;
padding:26px 0 0 0;
background:url('/images/custom_header.png') no-repeat 0 0;
}
First, we make the h1 virtually invisible via CSS by assigning a height and font-size of 0. Then we make sure it's invisible in all browsers by setting the letter-spacing and text-indent. The heading class has a top-padding which creates just enough space to show the image, which we set as the background. Super easy and effective!
You'll notice that I made two classes. I use the replace class as a global for the styles that are common to all replaced text, then the heading class has the unique styles.
Tagged: css, text replacement, tutorial
Ruby Net::FTP Tutorial
MAR
29
2009
Recently, at Plexus, a client needed the ability to import photos to their site from a remote FTP server. Perfect opportunity for me to learn about Net::FTP. Turns out it was surprisingly simple.
Let's say we want to login to the server 'ftp.sample.com' with the username 'test' and the password 'pass', then switch to the directory 'source/files' and get the file 'photos.zip'. There are a couple ways to do this. First, we have to create and FTP connection with:
# Login to the FTP server
ftp = Net::FTP.new('ftp.sample.com', 'test', 'pass')
# OR
ftp = Net::FTP.new('ftp.sample.com')
ftp.login('test', 'pass')
# Switch to the desired directory
ftp.chdir('source/files')
# Get the file we need and save it to our 'ftp_photos' directory
ftp.getbinaryfile('photos_2009-03-29.zip', 'ftp_photos/photos.zip')
# We're done, so we need to close the connection
ftp.close
You can also accomplish the same thing by passing a block to the open method, like so:
Net::FTP.open('ftp.sample.com') do |ftp|
ftp.login('test', 'pass')
ftp.chdir('source/files')
ftp.getbinaryfile('photos_2009-03-29.zip', 'ftp_photos/photos.zip')
end
Pretty straightforward and simple.
Create your own custom rails generator
FEB
22
2009
It's really easy to add a custom generator to your Rails application. Say you have a component you want to include in multiple projects, but you don't want to manually copy ALL of the files from project to project. At Plexus, we have an empty Rails project with basic styling and structure that we use for all new applications. We have several components that we wanted to simplify adding to new projects. So, we created a few custom generators that we can use to create the components with very little effort.
The first thing you need to do is add a generators folder inside the lib folder. In there you can add the files and folders for each custom generator. In this example, I'll use a Blog as the component I'm building a generator for.
Inside the generators folder, I created a blog folder (hint: whatever you name the folder will be how you call your custom generator). All of my files for the blog functionality will be in this folder. The two most important things in this folder are the actual generator file that will do all of the work and the templates folder which contains all the files to be copied. My blog generator file, blog_generator.rb looks like this:
class BlogGenerator < Rails::Generator::Base
def manifest
record do |m|
# Controllers
m.file "controllers/blog_controller.rb", "app/controllers/blog_controller.rb"
# Models
m.file "models/blog_post.rb", "app/models/blog_post.rb"
# Helpers
m.file "helpers/blog_helper.rb", "app/helpers/blog_helper.rb"
# Views
m.directory "app/views/blog"
m.file "views/index.html.erb", "app/views/blog/index.html.erb"
m.file "views/details.html.erb", "app/views/blog/details.html.erb"
m.file "views/feed.rss.builder", "app/views/blog/feed.rss.builder"
# Migration
m.migration_template "migrate/create_blog.rb", "db/migrate"
# Tests
m.file "test/fixtures/blog_posts.yml", "test/fixtures/blog_posts.yml"
m.file "test/functional/blog_controller_test.rb", "test/functional/blog_controller_test.rb"
m.file "test/unit/blog_post_test.rb", "test/unit/blog_post_test.rb"
# CSS and images
m.file "assets/blog_styles.css", "public/stylesheets/px_blogger.css"
m.file "assets/comment_add.gif", "public/images/comment_add.gif"
m.file "assets/comment.gif", "public/images/comment.gif"
m.readme "INSTALL"
end
end
def file_name
"create_blog"
end
end
Here is a breakdown of what is going on:
- The directory method will create the specified directory if it doesn't exist already.
- The file method will copy the specified file to the given directory.
- The migration_template file will copy the given migration file into the db/migrations folder using the file_name method defined at the bottom of the generator to name the file.
- The readme function prints out the contents of the INSTALL file after the generator script is called. You can use this file to put any extra instructions for the generator.
This is what the file structure looks like for the generator:
lib
\- generators
\- blog
\- blog_generator.rb
templates
\- assets
\- blog_styles.css
comment_add.gif
comment.gif
controllers
\- blog_controller.rb
helpers
\- blog_helper.rb
INSTALL
migrate
\- create_blog.rb
models
\- blog_post.rb
test
\- fixtures
\- blog_posts.yml
functional
\- blog_controller_test.rb
unit
\- blog_post_test.rb
views
\- index.html.erb
details.html.erb
feed.rss.builder
USAGE
All we need to do to run this generator is call script/generate blog.
Tagged: rails, generators, tutorial
Deploying a Merb application with the RailsMachine gem
FEB
07
2009
I recently launched a monthly bill/task tracking application I've been working on in my spare time. I used Merb so I could get some experience with the framework.
Plexus was kind enough to donate some server space on a RailsMachine server. Luckily, they recently added Passenger support to their awesome RailsMachine gem, so all I needed was to add a Rack config file to run my app on Passenger.
require 'rubygems'
require 'merb-core'
Merb::Config.setup(:merb_root => File.expand_path(File.dirname(__FILE__)),
:environment => ENV['RACK_ENV'])
Merb.environment = Merb::Config[:environment]
Merb.root = Merb::Config[:merb_root]
Merb::BootLoader.run
run Merb::Rack::Application.new
After that, I only needed to update the Capistrano deploy file to work with Merb and Passenger.
require 'railsmachine/recipes'
# The name of your application. Used for directory and file names associated with
# the application.
set :application, "listode"
# Target directory for the application on the web and app servers.
set :deploy_to, "/var/www/apps/#{application}"
# Primary domain name of your application. Used as a default for all server roles.
set :domain, "listode.com"
# Login user for ssh.
set :user, "deploy"
set :runner, user
set :admin_runner, user
# Rails environment. Used by application setup tasks and migrate tasks.
set :rails_env, "production"
# Automatically symlink these directories from curent/public to shared/public.
set :app_symlinks, %w{graphs}
set :deploy_via, :remote_cache
# =============================================================================
# ROLES
# =============================================================================
# Modify these values to execute tasks on a different server.
role :web, domain
role :app, domain
role :db, domain, :primary => true
role :scm, domain
# =============================================================================
# APPLICATION SERVER OPTIONS
# =============================================================================
set :app_server, :passenger # :mongrel or :passenger
# =============================================================================
# SCM OPTIONS
# =============================================================================
set :scm, :git # :subversion or :git
set :repository, "git@github.com:travisr/#{application}.git"
# =============================================================================
# CUSTOM CONFIGURATION
# =============================================================================
# action to symlink database file
namespace :deploy do
desc "Symlink database config file."
task :symlink_db do
run "ln -nfs #{shared_path}/system/database.yml #{release_path}/config/database.yml"
end
end
# Overwrite the default deploy.migrate as it calls:
# rake RAILS_ENV=production db:migrate
desc "Use datamapper to call autoupgrade instead of db:migrate."
deploy.task :migrate do
run "cd #{release_path}; rake db:autoupgrade MERB_ENV=production"
end
after 'deploy:update_code', 'deploy:symlink_db'
The custom section at the bottom sets up a symlink to my databases.yml file since I don't keep that in my git repo. I also have to override the migration action to use DataMapper's db:autoupgrade.
Tagged: rails machine, capistrano, passenger, merb, tutorial
Popular Posts
Search
Tags
actionmailer activerecord ajax apache apple barcamp caching capistrano centos code golf css db delete eager loading ebay email attachment erb flash ftp fun generators get haml helpers ie sucks javascript jquery lightbox lost merb net ftp paperclip passenger php plexus post presentation rails rails machine railsconf redesign rest rjs routes rss ruby ruby on rails safari script sinatra symfony text replacement tips tutorial twitter xhtml
Projects
© 2010 Travis Roberts. All rights reserved.