Aug 022012
 

In this tutorial I Will show how you can post twitter feeds using rails, but not required to be rails as it’s just a simple ruby class. Mostly it’s about how to use the Twitter gem.

It will cache the feeds in memcached. It does not do any database hit for performance.
Only queries twitter once an hour, which you can set default_ttl on the class object.

This is based on a Rails 3.2.7 App with Dalli as memcached backend.

Added to Gemfile:

gem ‘twitter’
gem ‘dalli’

Then Create an initializer file containing your twitter credentials:

1
2
3
4
5
6
7
8
9
 
# config/initializers/twitter.rb
 
Twitter.configure do |config|
  config.consumer_key = ENV["TWITTER_CONSUMER_KEY"]
  config.consumer_secret = ENV["TWITTER_CONSUMER_SECRET"]
  config.oauth_token = ENV["TWITTER_OAUTH_TOKEN_SECRET"]
  config.oauth_token_secret = ENV["TWITTER_OAUTH_TOKEN_SECRET"]
end

This is the model that does all the work. It fetches the timeline then stores in memcached.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# app/models/twitter_status.rb
 
 
class TwitterStatus
  attr_accessor :default_ttl
  attr_accessor :user
 
  # if no user is initialized, then use own screen_name from Twitter
  def user
    @user || Twitter.user.screen_name
  end
 
  # refresh time
  def default_ttl
    @default_ttl || 1.hour
  end
 
  def timeline
    unless is_fresh?
      reload
    end
    read_timeline
  end
 
  # Re-fetch timeline from twitter and saves it to the cache again
  def reload
    set_timeline
    set_timestamp
  end
 
 
private
  def cache_key
    "twitter_timeline_#{user.to_s}"
  end
 
  def cache_timestamp
    "twitter_timestamp_#{user.to_s}"
  end
 
  def fetched_at
    Rails.cache.read(cache_key)
  end
 
  def read_timeline
    Rails.cache.read(cache_key)
  end
 
  def set_timestamp
    Rails.cache.write(cache_timestamp, Time.now, timeToLive: default_ttl)
  end
 
  def set_timeline
    Rails.cache.write(cache_key, Twitter.user_timeline(user, include_entities: true))
  rescue
    Rails.logger.info("Error: Cannot connect to twitter or network down")
    Rails.cache.write(cache_key, [])
  end
 
  def is_fresh?
    fetched_at && fetched_at.is_a?(Time) && ((fetched_at + default_ttl) > Time.now)
  end
 
end

How to use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Initialize object
> my_timeline = TwitterStatus.new
 => #<TwitterStatus:0x007ff70dc50da8> 
 
# Default Time to store on memcached is 1 hour
> my_timeline.default_ttl
 => 3600 seconds
 
# Change the update interval to 10 minutes.
> my_timeline.default_ttl = 10.minutes
 => 600 seconds
 
# Get Array of recent tweets for Own Timeline
> my_timeline.timeline
 => [#<Twitter::Status:0x007ff70da00468 @attrs={. . . . 
 
# Get latest single tweet on your timeline:
> my_timeline.timeline.first.text
 => "Hello world http://t.co/123456" 
 
 
# Get timeline of another user
> user_timeline = TwitterStatus.new
 => #<TwitterStatus:0x007ff70dc98860>
> user_timeline.user = "fred_on_rails"
 => "fred_on_rails" 
 
# Get fred's last tweet from timeline
1.9.3-p194 :039 > user_timeline.timeline.first.text
 => "Rainwater Crimes: Man gets jail and fines for collecting on his own land http://t.co/Qzn5NWpS" 
 
# Force reload, it refetches from twitter and saves it to the cache again
> user_timeline.reload
 => true

In the views you could display like this:

1
2
3
4
5
6
7
# app/helpers/twitter_helper.rb
 
module TwitterHelper
  def url_for_twit(user,status_id)
    "https://twitter.com/#{user}/status/#{status_id}"
  end
end

In a controller action (example for a logged in user profile page)

1
2
3
  @twitter_status = TwitterStatus.new
  @twitter_status.user = current_user.twitter_screen_name
  @twitter_status.default_ttl = 30.minutes

Erb view:

1
2
3
4
5
6
7
8
9
10
11
<h3>Twitter Updates</h3>
<ul>
  <% @twitter_status.timeline[0..5].each do |status| %>
    <li>
      <%= link_to(status.text, url_for_twit(@twitter_status.user, status.id), target: 'blank') %>
      <span class="twitter-feed-date">
        <%= time_ago_in_words status.created_at %> ago
      </span>
    </li>
  <% end %>
</ul>

Nov 152011
 

If you need to use the Rails API offline, you can download it here:

rails311.tar.bz2 1.4M Nov 15 08:04

The package contants multiple gems rdoc: railties-3.1.1 rails-3.1.1 actionmailer-3.1.1 activemodel-3.1.1 activeresource-3.1.1 actionpack-3.1.1 activerecord-3.1.1 activesupport-3.1.1 sass-3.1.10 coffee-rails-3.1.1 coffee-script-2.2.0

You can browse online if you wish so : /rails311/index.html

Generated by sdoc

 Posted by at 3:11 pm
Oct 122011
 

This is a ruby on Rails demo app using Address autocomplete with google places API.

I was experimenting with google places and I found it to be quite awesome.

In this app you can search for a geocode address or establishments, move the marker and get the the GPS coordinates, and also get the gps coordinates out the search results.

it’s also possible to restrain the autocomplete results by limiting it to bounds:

autocomplete.setBounds(defaultBounds);

here is the demo app: http://electric-sunrise-8410.heroku.com/
source: https://github.com/fred/google_places_autocomplete

 Posted by at 2:32 am
Jul 302011
 

Bye Bye Macports, Welcome Homebrew

Definition
Homebrew: The missing package manager for OS X

Why? well, the reality is, macports is not that good anymore.
Once you have many packages installed and start updating, everything start to break apart, lot’s of failing packages.

Homebrew is very easy to install, it’s fast and simple. That means you can make your own homebrew formula for your package so easily. oh, and homebrew is in ruby! :)

Back to topic, this is you how you get rails with mysql up and running with homebrew and rvm.

Clean up

To make sure to have a clean install, I recommend removing any previous .rvm installation and previous Xcode.

$ rm -rf ~/.rvm/
$ sudo rm -rf /Developer

1. Xcode

Install Xcode from AppStore. it’s 1+ GB download so it may take a while.
after it’s downloaded it will not install automatically, you need to open Applications and install again from there, the name will be “Install Xcode”.
You also need to install Command Line Tools for Xcode.

Better way is to go to https://developer.apple.com/downloads/index.action and download from there, you will have to login with a free apple developer account.
Download the 2 minimum require files

- Xcode 4.3.1 for Lion (1.85 GB)
- Command Line Tools for Xcode (171.70 MB)

Update: If you don’t want to download and install huge XCODE (3.0GB) :
https://github.com/kennethreitz/osx-gcc-installer
It allows you to install the essential compilers, GCC, LLVM, etc.
PS: I have not tested it
Thanks JP for the tip.

2. Install HomeBrew

UPDATE: in the comments some people recommended to do create the folder “/usr/local/Cellar” before hand, due to some bug on homebrew.

mkdir -p /usr/local/Cellar
$ /usr/bin/ruby -e "$(/usr/bin/curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"

Installation instructions: https://github.com/mxcl/homebrew/wiki/installation

3. install RVM

$  bash -s master < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

Above im using the master branch, so that it works with xcode 4.3.1

Then after RVM is installed run these two 'one-line' commands, the second command will reload your bash with RVM.

$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
$ source ~/.bash_profile

Details instructions: http://beginrescueend.com/rvm/install/

Note: you may have to add "--with-gcc=clang" to rvm for installing ruby 1.9.2 if you have Xcode 4.3+
Read this: http://stackoverflow.com/a/9651747/1107516

4. Install ruby 1.9.3-p125

OS X Lion comes with Ruby-1.8.7-p249, but we all want ruby 1.9.2/1.9.3 right?
RVM head and Ruby 1.9.3-p125 supports XCODE 4.3.1 http://www.ruby-lang.org/en/news/2012/02/16/ruby-1-9-3-p125-is-released/

$ rvm install 1.9.3-p125
$ rvm use ruby-1.9.3-p125
$ gem install rails bundler unicorn pg 
... and so on ...

I tested both ruby-1.9.3-head and ruby-1.9.3-p0, and 1.9.3-p125, and it works well with all my apps. Ruby 1.9.3 is faster than 1.9.2 booting rails, and way way faster than 1.8.7. So let's use the lastest Stable Ruby (1.9.3-p0)

See: Rails booting a lot faster.

NOTE: For Heroku I recommend you to use ruby-1.9.2-p290, if you use taps ("heroku db:pull/push")

Optionally you might want to install GIT, wget, ack, imagemagick and any other mighty software tools for daily use.

Example apps I'm usually required to install:

# brew install git ack wget curl redis memcached libmemcached colordiff imagemagick nginx sqlite libxml2 libxslt readline v8 rsync sphinx lzma geoip lzo 

5. Install Mysql

$ brew install mysql

one-line command:

$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp

Once mysql is installed you might want it to load automatically each time you start your mac.

$ mkdir -p ~/Library/LaunchAgents
$ cp /usr/local/Cellar/mysql/5.5.14/com.mysql.mysqld.plist ~/Library/LaunchAgents/
$ launchctl load -w ~/Library/LaunchAgents/com.mysql.mysqld.plist

*check that the version I use here is 5.5.14

6. Troubleshooting:

if you have problems with mysql "cannot connect to /tmp/mysql.sock"
then create a file /usr/local/etc/my.cnf and add this:

[client] 
port = 3306 
socket = /tmp/mysql.sock 
[mysqld] 
bind-address = 127.0.0.1
port = 3306 
socket = /tmp/mysql.sock 

if encounter errors with homebrew run this command and follow recommendations:

$ brew doctor

update: If you end up with Segmentation fault or cannot install Ruby-1.8.7, you might want to try this solution:

$ export CC=/usr/bin/gcc-4.2
$ rvm install ruby-1.8.7 

Important, also read this if you have Xcode 4.3.1+

http://stackoverflow.com/questions/9651670/issue-updating-ruby-on-mac-with-xcode-4-3-1

by the way this is my /usr/local/etc/my.cnf optimized file, when using this file you may have to recreate your db

$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp
[client] 
port = 3306 
socket = /tmp/mysql.sock 

[mysqld] 
event_scheduler = ON 
skip-character-set-client-handshake 
collation_server = utf8_unicode_ci 
character_set_server = utf8 

bind-address = 127.0.0.1
port = 3306 
socket = /tmp/mysql.sock 
max_connections = 20

table_open_cache = 256
max_allowed_packet = 32M 
binlog_cache_size = 1M 
max_heap_table_size = 64M 

read_buffer_size = 2M
read_rnd_buffer_size = 2M
sort_buffer_size = 4M
join_buffer_size = 512k
 
thread_cache_size = 2 
thread_concurrency = 2
query_cache_size = 16M 
query_cache_limit = 2M 

default-storage-engine = INNODB
thread_stack = 192K 
transaction_isolation = REPEATABLE-READ 
tmp_table_size = 64M 


# MyISAM Options 

key_buffer_size = 32M
bulk_insert_buffer_size = 32M
myisam_sort_buffer_size = 32M
myisam_max_sort_file_size = 256M
myisam_repair_threads = 1 
myisam_recover 

# INNODB Options
innodb_additional_mem_pool_size = 8M
innodb_buffer_pool_size = 64M
innodb_thread_concurrency = 2
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 8M
innodb_log_file_size = 8M
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 90
innodb_flush_method = O_DIRECT
innodb_lock_wait_timeout = 120
innodb_file_per_table

[mysqldump] 
quick 
max_allowed_packet = 16M 

[mysql] 
no-auto-rehash 

[myisamchk] 
key_buffer_size = 64M
sort_buffer_size = 64M
read_buffer = 16M
write_buffer = 16M

[mysqlhotcopy] 
interactive-timeout 

UPDATED (Mar 14, 2012):
* Fixed homebrew install URL
* changed from "#" to "$" to avoid confusion of running commands as root

EDITED (Feb 10, 2012):
* updated for new RVM
* source .bash_profile after editing it.
* decreased memory settings for mysql
* using ruby-1.9.3-p0
* fixed minor bugs

 Posted by at 2:06 am
Nov 192010
 

This is a monit recipe for a rails app with 4 Unicorn threads using SOCKET. The app averages a total memory usage of 600 MB.
If it goes over 800 MB send email alert only.
If over 860 MB, reload the app.
Also if it’s using too much CPU, alert by email.

I use unicorn_rails on socket mode with nginx, and preload_app = true.

check process myapp_unicorn 
  with pidfile /var/www/apps/my_app.com/shared/pids/unicorn.pid
group unicorn
if totalmem > 800 MB for 2 cycles 
  then alert
if totalmem > 860 MB for 2 cycles 
  then exec "kill -HUP `cat /var/www/apps/my_app.com/shared/pids/unicorn.pid`"
if cpu > 40% for 2 cycles then alert
if cpu > 20% for 4 cycles then alert
if failed 
  unixsocket /var/www/apps/my_app.com/shared/pids/unicorn.sock 
  then alert

note: the HUP signal will reload the children processes without reloading code changes. This is fast and desirable.

Resources:
http://unicorn.bogomips.org/SIGNALS.html
http://mmonit.com/monit/documentation/monit.html

 Posted by at 7:18 pm  Tagged with:
Aug 192010
 

UPDATE: New version for OS X Lion HERE

I choose the simple and I believe clean way to use everything from macports and passenger.

The advantage is that it’s all isolated from the OS X system and using latest cutting edge version of softwares.

I assume you have textmate, because it’s easy to edit files that need sudo access. Textmate will just ask for your password.

Try and download the 30 days trial for easy of this tutorial. http://macromates.com/

Trust me, you will love Textmate, it’s state of the art editor.

ps: I use “mate” instead of “open -a TextMate” but not everyone might have the mate symlink.

Requirements:

  • Snow Leopard 10.6.4 or greater
  • Xcode 3.2.3, 2.4.1 or greater
  • Admin privileges on your mac.

Software preliminary:

  • Mysql 5.1.49 (macports)
  • Ruby 1.8.7 (macports)
  • Apache 2.2.9 (part of OS X)
  • Rubygems (download)
  • passenger (gem)
  • ImageMagick
  • rmagick

1. Preparing System

If you are upgrading from Leopard to Snow Leopard, I recommend you delet your old installation.

sudo rm -rf \
    /opt/local \
    /Applications/DarwinPorts \
    /Applications/MacPorts \
    /Library/LaunchDaemons/org.macports.* \
    /Library/Receipts/DarwinPorts*.pkg \
    /Library/Receipts/MacPorts*.pkg \
    /Library/StartupItems/DarwinPortsStartup \
    /Library/Tcl/darwinports1.0 \
    /Library/Tcl/macports1.0 \
    ~/.macports

1.1 Prepare PATH environment:

$ open -a TextMate ~/.bash_profile

Edit your ~/.bash_profile file and add these 2 line.
Check if they are not there already.

export PATH=/opt/local/bin:/opt/local/sbin:$PATH
export MANPATH=/opt/local/share/man:$MANPATH

1.2 Download and Install Xcode

http://developer.apple.com/technologies/xcode.html

1.3 Download Macports and install

Download Page: http://www.macports.org/install.php

Download Direct Link: http://distfiles.macports.org/MacPorts/MacPorts-1.9.2-10.6-SnowLeopard.dmg

You might use this guide for installing Macports:

Full Install Guide: http://guide.macports.org/#installing

1.3.1 Update macports

sudo port -v selfupdate

2. Mysql

2.1 Intall Mysql

sudo port -v install mysql5-server mysql5

2.2 Make mysql autoload on startup

sudo port load mysql5-server
sudo -u mysql mysql_install_db5

3. Memcached (Optional)

sudo port -v install memcached libmemcached

3.1 Autoload memcached on startup

sudo port load memcached

4. Ruby, Rubygems, Rails, other gems

4.1 Install Ruby from macports

sudo port -v install ruby
$ ruby -v
ruby 1.8.7 (2010-08-08 patchlevel 302) [x86_64-darwin10]

4.2 download rubygems from http://rubygems.org/pages/download

cd /tmp
wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz
tar xpf rubygems-1.3.7.tgz
cd rubygems-1.3.7
sudo ruby setup.rb

4.3 Install rails, rake, rspec etc.

sudo gem install rake rails thin tzinfo capistrano ruby-debug rspec

extra:

4.4 install mysql gem

sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_config

5. ImageMagick, Rmagick and mini_magick (Optional)

lets install ImageMagick with support for JPEG, TIFF, WMF, PDF, and PNG images, and for Postscript and TrueType fonts.

sudo port -v install tiff -macosx imagemagick +q8 +gs +wmf
sudo gem install mini_magick rmagick

Test rmagick

$ irb -rubygems -r RMagick
>> puts Magick::Long_version
This is RMagick 2.13.1 ($Date: 2009/12/20 02:33:33 $) Copyright (C) 2009 by Timothy P. Hunter
Built with ImageMagick 6.6.3-0 2010-08-19 Q8 http://www.imagemagick.org
Built for ruby 1.8.7
Web page: http://rmagick.rubyforge.org
Email: rmagick@rubyforge.org
=> nil

6. Passenger

6.1 Install Passenger gem

sudo gem install passenger

6.2 Check Passenger path

passenger-config --root
 -> /opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.15

6.3 Build passenger for apache

follow instructions on screen

sudo passenger-install-apache2-module

6.4 Enable Passenger on apache:

open -a TextMate /etc/apache2/extra/httpd-passenger.conf

Put this on that file, change wherever necessary for your directories.

LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.15/ext/apache2/mod_passenger.so
PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.15
PassengerRuby /opt/local/bin/ruby
PassengerMaxPoolSize 6  # maximum global rails servers
PassengerMaxInstancesPerApp 2  # maximum rails servers per application
RailsFrameworkSpawnerIdleTime 1800
RailsAppSpawnerIdleTime 600
PassengerPoolIdleTime 600
PassengerMaxRequests 1000  # after 1000 requests will restart server, to skip memory leak :)
 
# Enabling NameBased Virtualhost
NameVirtualHost *:80
 
# my rails app virtual host 1
<VirtualHost *:80>
    ServerName my-rails-app.local
    DocumentRoot "/Users/fred/rails/my-rails-app/public" # change this to match your folder
    RailsEnv "development"
   <Directory /Users/fred/rails/my-rails-app/public>
        # change this to match your folder
        # MultiViews must be turned off
        Options -MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
    # logs are optional, change this to match your folder
    CustomLog  "/Users/fred/rails/my-rails-app/log/access_log" combined
    ErrorLog   "/Users/fred/rails/my-rails-app/log/error_log"
</VirtualHost>
 
# my rails app virtual host 2
<VirtualHost *:80>
    ServerName myapp-xyz.local
    DocumentRoot "/Users/fred/rails/myapp-xyz/public"  # change this to match your folder
    RailsEnv "development"
    <Directory /Users/fred/rails/my-rails-app/public>
        # change this to match your folder
        # MultiViews must be turned off
        Options -MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
    CustomLog  "/Users/fred/rails/myapp-xyz/log/access_log" combined
    ErrorLog  "/Users/fred/rails/myapp-xyz/log/error_log"
</VirtualHost>

6.5 Enable Virtual host on apache:

open -a TextMate /etc/apache2/httpd.conf

Add this new line at the bottom:

# Include Passenger ModRails config file
Include /private/etc/apache2/extra/httpd-passenger.conf

6.6 Add your .local domain to /etc/hosts/

open -a TextMate /etc/hosts

Add this line to that file and change to the name of your choosen application

You might add as many as you want, each line for each that ServerName on your VirtualHost blocks

127.0.0.1 my-rails-app.local
127.0.0.1 myapp-xyz.local

I have more than 50 .local apps in there.

5 Start Apache

first let’s test apache configuration:

apachectl configtest

if you get “Syntax OK” then you are ready to start it

sudo apachectl start

If you want Apache to autostart when you boot your computer,
then enable Web Sharing from preferences.

7. Final

go to your browser and open the url of your application http://my-rails-app.local

If it works, congratulations.

If didn’t work, let me know here in the comments.

Extras

Nokogiri

  sudo port -v install libxml2 libxslt
  sudo gem install nokogiri -- --with-xml2-include=/opt/local/include/libxml2 --with-xml2-lib=/opt/local/lib --with-xslt-dir=/opt/local

Sqlite

sudo port install sqlite3
sudo gem install sqlite3-ruby

9. Sphinx, thinking-sphinx, sphinxsearchlogic

sudo port install sqlite3
sudo gem install thinking-sphinx sphinxsearchlogic

Update:

From the comments, some people might want to enable php and your Sites folder.

To be able to enable php and others you will have to enable another default vhost with localhost as servername.

Edit the file /etc/apache2/httpd.conf to enable vhosts

# Virtual hosts
Include /private/etc/apache2/extra/httpd-vhosts.conf

then open /private/etc/apache2/extra/httpd-vhosts.conf file,
delete or comment everything from there and add this block only:

#
# Use name-based virtual hosting.
#
NameVirtualHost *:80
 
# Change /Users/fred/ to your appropriate login name
<VirtualHost *:80>
    ServerName localhost
    DocumentRoot /Users/fred/Sites/
    RewriteEngine On
    DefaultType text/html
    <Directory "/Users/fred/Sites">
        DefaultType text/html
        Options +ExecCGI FollowSymLinks Indexes
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

Links and Resources

http://rmagick.rubyforge.org/install-osx.html

http://wiki.github.com/tenderlove/nokogiri/what-to-do-if-libxml2-is-being-a-jerk

http://www.macports.org/install.php

http://guide.macports.org/#installing

http://distfiles.macports.org/MacPorts/MacPorts-1.9.1-10.6-SnowLeopard.dmg

http://rob.by/2009/installing-mysql-via-macports-on-snow-leopard-for-ruby-development/

http://macromates.com/

http://github.com/joost/sphinxsearchlogic

http://www.sphinxsearch.com/

 Posted by at 3:36 pm

Switch to our mobile site