Ruby Module Mixin Awesomeness

The deeper I dig into Rails, the more I need to know about Ruby.  I have been learning more about how Ruby does OO.  I came to Ruby from Java and at first things like modules were confusing for me.  Recently I discovered the power of mixin modules.  I was trying to figure out how to put my models into a plugin and then override or add additional functionality to those models.  My main reason for doing this was to change the database referenced in the “use_db” plugin.  I had a hard time finding an elegant way to do it, but mixin modules really helped me do it in simple way.

So what do mixin modules do?  Basically they allow you to code instance methods into a module and then include the module in a class.  The class will then have access to the instance methods in a module.  Pretty nice when you have shared functionality between models.  You can code one module and include it in several models.

Here is an example:

module LoudModule
  def explode
    "BOOM!"
  end
end

class BottleRocket
  include LoudModule
end

class FireCracker
  include LoudModule
end

firecracker = FireCracker.new
p firecracker.explode

bottlerocket = BottleRocket.new
p bottlerocket.explode

As you can see firecracker and bottlerocket both have access to the “explode” instance method in the module.

Now to make this work with a Rails plugin where you need a model base class:

module BaseWidget
  self.included?(base)
    base.belongs_to :manufacturer
  end

  def some_instance_method
    "test"
  end
end

class Widget < ActiveRecord::Base
  unloadable
  use_db :prefix => "mydatabse_prefix_"
  include BaseWidget
  def some_new_instance_method
    "test2"
  end
end

This is pretty cool because it will allow you to define a base class for your model that you can reuse in different applications. The self.included? block allows you to load use the instance methods from the base class (ActiveRecord::Base in this case). So Widget will have access to all the associations, named_scopes and act_as* methods from the Base class.

Setting up a Ruby on Rails stack on Rackspace Cloud

I have been using Rackspace Cloud for several months and it is the most advanced web hosting I have ever seen by a long shot.   Rackspace has always had great customer service, but I always thought the pricing was ridiculous compared to similar options.  Not anymore.. with the Cloud you can get a cheap, flexible and scalable solution (I’m still keeping an eye on reliability.. time will tell).  Currently I have 9 servers running on the cloud, but I am still waiting to move my flagship site to the cloud..  reliability and performance seem great so far, but I want to give it a few more months before I commit my highest traffic site to it.  Its pretty easy to get a Rails stack running on the cloud using a simple shell script.  Here is what I am currently using.  Note that some of the versions may be outdated when you read this article, so you may need to update the script.  Once you have this server loaded, you can create a backup and then create more servers based on that backup.  You can literally have a working dedicated Rails server in less than 5 minutes.  I am using a CentOS 5.4 server on the cloud

Server setup shell script:  setup.sh

##############
#  SETUP.SH  #
##############

#————————————————————————————————————-
# INSTALL SOFTWARE AND DEPENDENCIES WITH YUM
#————————————————————————————————————-
rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
yum -y install mysql mysql-server mysql-devel gcc make zlib zlib-devel openssl openssl-devel git expect pcre pcre-devel readline-devel libxml2-devel libxslt-devel

#————————————————————————————————————-
# CREATE A DIRECTORY FOR DOWNLOADED FILES AND INSTALL RUBY
#————————————————————————————————————-
mkdir /home/Downloads
cd /home/Downloads
wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p174.tar.gz
tar -xvf ruby-1.8.7-p174.tar.gz
cd ruby-1.8.7-p174
./configure
make
make install

#———————————————————
# INSTALL RUBYGEMS
#———————————————————
cd ..
wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz
tar -xvf rubygems-1.3.5.tgz
cd rubygems-1.3.5
ruby setup.rb
cd /

#————————————————————————————————————-
# INSTALL GEMS – YOU WILL NEED RAILS, MONGREL AND PROBABLY MYSQL.
# THE OTHERS ARE JUST SOME COMMON ONES I USE.
#————————————————————————————————————-
gem install –no-rdoc –no-ri rails -v=2.3.2
gem install –no-rdoc –no-ri mime-types
gem install –no-rdoc –no-ri mysql — –with-mysql-lib=/usr/lib64/mysql
gem install –no-rdoc –no-ri fastercsv
gem install –no-rdoc –no-ri mongrel mongrel_cluster
gem install –no-rdoc –no-ri json
gem install –no-rdoc –no-ri mechanize

#————————————————————————————————————-
# CHANGE MYSQL TO STARTUP SCRIPT AND START SERVER
#————————————————————————————————————-
mv /etc/rc3.d/K36mysqld /etc/rc3.d/S36mysqld
/etc/init.d/mysqld start

#————————————————————————————————————-
# INSTALL NGINX WEB SERVER & copy a working config file (you create this) to the config dir
#————————————————————————————————————-
wget http://sysoev.ru/nginx/nginx-0.7.64.tar.gz
tar -xvf nginx-0.7.64.tar.gz
cd nginx-0.7.64
./configure –sbin-path=/sbin/nginx –conf-path=/usr/local/nginx/nginx.conf –pid-path=/usr/local/nginx/nginx.pid –with-http_ssl_module –with-md5=auto/lib/md5 –with-sha1=auto/lib/sha1
make
make install
# THIS IS A DEFAULT NGINX CONFIG THAT I UPLOAD TO THE SERVER.  COPY NGINX CONFIG TO THE APPROPRIATE DIR & RESTART
cp /root/nginx.conf /usr/local/nginx/nginx.conf
/sbin/nginx

#————————————————————————————————————-
# OPEN UP SECURITY FOR MONGREL
#————————————————————————————————————-
echo 1 >/selinux/enforce
/usr/sbin/setsebool -P httpd_can_network_connect=1

#————————————————————————————————————-
# OPTIONAL – SECURITY – THIS IS A DEFAULT IPTABLES SCRIPT I UPLOAD TO THE SERVER.  COPY IPTABLES SCRIPT OVER
#————————————————————————————————————-
cp /root/iptables_config /etc/sysconfig/iptables
/etc/init.d/iptables restart

#*******************************************************************************************************
# NOTE: THE REST OF THIS SCRIPT IS USED TO AUTOMATE PULLING YOUR APP CODE FROM GITHUB,
# RAKING THE DB, AND ADDING STARTUP SCRIPTS FOR MONGREL, AND STARTING MONGREL INSIDE
# YOUR RAILS APP DIR.  IF YOU ARE USING CAPISTRANO, SOME OF THIS IS PROBABLY NOT NECCESSARY, BUT I
# HAVE BEEN TOO LAZY TO LEARN CAP.. THIS METHOD WORKS FINE FOR WHAT I DO
#*******************************************************************************************************

#————————————————————————————————————-
# OPTIONAL – CREATE RAILS DIR.. I ALWAYS USE THIS DIRECTORY.. MODIFY TO YOUR TASTE-> /RAILS_APPS
#————————————————————————————————————-
mkdir rails_apps

#————————————————————————————————————-
# OPTIONAL – IF YOU ARE USING GITHUB, YOU WILL WANT TO COPY YOUR SSH KEYS.
# I JUST FTP THE KEY FILES TO MY SERVER ALONG WITH THE SETUP SCRIPT.
# I PLACE ALL THE FILES I AM USING IN /ROOT/
#————————————————————————————————————-
mkdir /root/.ssh
cp /root/id_rsa.pub /root/.ssh/id_rsa.pub
cp /root/id_rsa /root/.ssh/id_rsa
cp /root/known_hosts /root/.ssh/known_hosts
chmod 700 /root/.ssh/*

#————————————————————————————————————-
# OPTIONAL – GET THE APP FROM GITHUB
#————————————————————————————————————-
cd /rails_apps
git clone git@github.com:yourusername/yourproject.git
mkdir /rails_apps/yourproject/log
mkdir /rails_apps/yourproject/tmp/pids

#————————————————————————————————————-
# OPTIONAL – RAKE THE DB
#————————————————————————————————————-
cd /rails_apps/yourapp
rake db:migrate

#————————————————————————————————————-
# OPTIONAL – ADD MONGREL STARTUP SCRIPT AND PUT IN RC.LOCAL AND START MONGREL
#————————————————————————————————————-
cp /root/server_start.sh /rails_apps/server_start.sh
chmod 700 /rails_apps/*.sh
echo “/rails_apps/start_server.sh” >> /etc/rc.local
/rails_apps/server_start.sh

This worked for me last time I tried it. YMMV

Installing memcached and using memcached with Rails on CentOS 5.x

Memcached is a great way to speed up your rails app using caching.  One great feature I like is that you can set the cache expiration date.  Great for pages or code blocks that only update every day, hour, etc..

I am installing this on a clean, stripped-down version of CentOS on Rackspace cloud.  So first things first, you need to install a c compiler and make

>yum install gcc
>yum install make

Next you need to install libevent

> wget http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz
> tar -xvf libevent-1.4.13-stable.tar.gz
> cd libevent-1.4.13-stable
>./configure && make
> make install

Good to go.. now you will need to download and install memcached

> cd ..
> wget http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz
> tar -xvf memcached-1.4.4.tar.gz
> cd memcached-1.4.4
> ./configure && make
> make install

Now you can start memcached

> /usr/local/bin/memcached -u nobody &

I also add this command (without the ‘&’ at the end) to /etc/rc.local, so memcached starts automatically if the server is rebooted

When you start memcached you may get the following error:

/usr/local/bin/memcached: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory

Here is the fix:

Create this file

> nano /etc/ld.so.conf.d/libevent-i386.conf

add the following line to the file and close and save it:

/usr/local/lib/

then run this command

> /sbin/ldconfig

You should be able to start memcached now without the error

>/usr/local/bin/memcached -u nobody &

You can get the status like this if you have ‘nc’ installed (yum install nc, if not)

> echo stats | nc 127.0.0.1 11211

Memcached is now installed and working correctly.  Do the following to configure your rails app to work with it.  On the server that contains your Rails code:

> gem install memcache-client

Uncomment or add this line to /your-rails-app/config/environments/production.rb

config.cache_store = :mem_cache_store

Add caching code to your rails app.  For example you could cache an action in the ProductsController like this:

class ProductsController < ApplicationController
   caches_action :some_action, :expires_in => 1.hour
   ...
end

restart your rails app and you should be good to go

More named_scope stuff. Chaining a named scope to a normal Rails find method

I had the problem recently where I was using a slave database on a website that is similar to another one, but has some differences in the data that needed to be displayed.  In order to display the correct data, I have to use a flag in one table that tells me whether the data can be displayed on the secondary website (that uses the slave database).  Instead of adding to the conditions of every find I have, I decided to create a named scope with the condition in there, like so:

named_scope :filter_non_secondary_website_data, :conditions=>”secondary_website=1″

I know you can chain named_scopes to each other, but I was wondering if I could chain it to a find method also.  At first I appending it to the end of a find like this

records = SomeModel.find(:all,:conditions=>” you=’awesome’ “).filter_non_secondary_website_data

Nope that didnt work.  If I remember the error was something about that method not existing for type array.  In order to make this work you need to append it to the beginning so the find can combine it with its SQL.  Here is the correct way which will append the SQL “AND secondary_website=1″ to the find’s SQL

records = SomeModel.filter_non_secondary_website_data.find(:all,:conditions=>” you=’awesome’ “)

That works.  There is probably a way I could override the find method in the model and add this code.  Anybody know??  I just searched my project for all finds and added the method.  Not exactly an optimal solution if you have a hundred finds.. but anyways, pretty cool that you can chain a named scope to find if you need to.

Space below an image when padding and margin are set to 0

I spent over an hour trying to figure this out, which was way too long, so I thought I would post the solution here. The problem was that I had 2 images that we supposed to sit on top of each other vertically with no space or padding between them. I set the div that contains them to the same width as the image and specified float:left and margin/padding to be 0 as you can see in the code below. I was still getting a few pixels of vertical space between the 2 images. I messed around in firebug for an hour changing styles adding another div around the image, etc.. but nothing worked. Finally I stumbled upon a site that explained that FF and IE will put vertical spacing between images automatically.  You need to specify the display property on the image as block if you want to remove this.  I added display:block to the code and it worked.  Vertical image spacing removed in Firefox and IE!

<div style="margin: 0pt; padding: 0pt; float: left; width: 150px;">
  <img style="margin: 0pt; padding: 0pt; width: 150px; float: left;display:block;" src="some-image.gif" alt="" />
  <img style="margin: 0pt; padding: 0pt; width: 150px; float: left;display:block;" src="some-image.gif" alt="" />
</div>

Create database from the command line or shell script

I am writing a shell script that to setup my server and I need to create a database as part of this process.  Its pretty easy to do.  You can create a database from the command line without logging in to mysql interactive mode.  Here is the code

>mysql -u root -pyourpassword -e “create database some_database_name;”

NOTE: when I pasted this into bash, I had to change the quotes.. I guess wordpress converts them to a different encoding

Retrying MySQL slave query after an error

I did something stupid today.  I was logged into my slave and thought I was logged into the master.  I altered a table and then realized I was on the wrong server.  So I logged into master and altered the same table.  This created an error when the slave tried to replicate, because the column in the table it was altering already existed.  So the replication could not continue.  I ran this command:

>SHOW SLAVE STATUS \G;

This showed me the error, so I went back and deleted the column on the slave so the alter statement on the slave would finish without error.  Then all you have to do is stop slave and then start slave

>STOP SLAVE;

>START SLAVE;

The slave should catch up to the master shortly.  NOTE TO SELF… make slave user read only.

su on Mac

I am fairly new to the Mac and I was trying to figure out how to become su when using the Mac terminal. Apparently Mac does not come with su enabled by default.  When I tried the command “su”, it prompted me for a password, but I don’t remember setting a password before.  So in order to get super user access, you have to set the password for root first.  All you need to do is issue this command and you will be able to “su”

>sudo passwd root

Enter your user account password and then enter the new root password twice.  After that issue the “su” command and enter the password you just created.  You have super user access now.

Using named_scope for object filtering

One of the cool new features in Ruby on Rails is the named_scope.  You can put a named_scope in your model as a way to do a customized find by just calling a name.  Here is an example of a simple named_scope.  This named scope gets all the widgets that are blue.  You can call it like this: Widget.blues

class Widget < ActiveRecord::Base
  named_scope :blues, :conditions=> "color='blue'"
end

Thats pretty cool huh? Very DRY if you are going to be using this quite a bit. Here is a more complex example where you can insert a parameter using lambda.

  named_scope :above_price, lambda { |*args| {:conditions => ["price>?",args.first] } }

  #get all widgets with price above $25
  Widget.above_price(25)

Even cooler…
Now here is something I like even better that I was not expecting, but it seems to work. I am able to chain these together to filter out different widgets based on criteria. This is useful in an application that needs to allow users to filter out certain content based on criteria. Lets say you have a list full of widgets of all kinds, but the user only wants to see widgets that are blue and cost more than $25. You can add some check boxes and inputs to your view with a submit button and let the user choose different criteria so they can find the widget they are looking for. Then you can filter out the widgets with named scopes in your controller

widgets = Widget.all
if params[:is_blue]
  widgets = widgets.blues
end
if params[:above_price]
  widgets = widgets.above_price(params[:above_price])
end
#now you would have all the blue widgets above whatever price the user entered in the field "above_price"

#If I remember correctly, you can also call them by chaining them together if you need to
widgets = widgets.blue.above_price(25)

I think this is a pretty elegant solution for doing object filtering in Rails. Go named_scope! You crazy!

Creating a Facebook (iFrame) app using Ruby on Rails & Facebooker

I recently had the pleasure of creating a Facebook app with Ruby on Rails. At first I thought I might try to write my own code to interact directly with the Facebook API, but after looking at it a bit, I decided I better find some existing software to save me some time. Really the only good choice is Facebooker. rFacebook is also another choice, but it looks like it was abandoned a while ago. Apparently Facebook has made quite a few changes to the API in the last year or so. After diving into development I found that Facebooker is not exactly up to date either. A workaround is pretty easy to code, so I will show you that here.

First thing you want to do when creating a facebook app is to log on to Facebook Developer -> http://www.facebook.com/developers/. They have 2 sites for this and dont ask me why. The other one is developer.facebook.com. Do not use that one, because there is no way to edit your app from that page.

From http://www.facebook.com/developers/, click “Set up New Application” and enter an app name. After that you will go to the “Edit” screen for your application. There are a ton of different things you can configure, like the icon, etc.., but for now you just need to worry about your canvas settings. Click “Canvas” in the left side menu. Enter a name for your app: http://apps.facebook.com/your-app-name-goes-here . Next is the most important part, the “Canvas Callback URL”. For this, you need to enter the URL of your application. Since this is going to be an iFrame application, your app will be retrieved from your servers. So I entered: http://www.myapp.com/facebook/canvas. Next make sure you select “iFrame” under canvas render method. Save your changes and its time to start coding with Rails

Here is a screenshot of my settings:
Picture 3

You will need to install facebooker as a plugin. Follow the instructions on github – http://github.com/mmangino/facebooker

Rails Stuff
1. Create a controller called “facebook_controller.rb”
2. Add an action for your canvas page. This will be like the welcome page for your application
3. Add “ensure_authenticated_to_facebook” to the top of your controller. I will talk about this in more detail later.

4. Set up your view (canvas.html.erb) with whatever you want in it. “Hello world”

class FacebookController < ApplicationController
  ensure_authenticated_to_facebook

  def canvas
  end
end

Since you are the developer and you set up the app in facebook, it will already be installed in your facebook account. You can test it by going to http://apps.facebook.com/name-of-your-app-goes-here
You should see your app render in the iframe. Now lets move on to where the app actually does something. Create a link in your view to go to another action that will count your friends

canvas.html.erb


<%=link_to "count_friends", :action=>"count_friends" %>

Now you need to add the action to your facebook_controller.rb:

def count_friends
  @count = 0
  #this session variable is set automatically by the facebooker plugin
  fbsession = session[:facebook_session]
  #iterate thru your friends.  fbsession.user grabs your user account and then .friends pulls in all your friends
  fbsession.user.friends.each do |user|
    @count += 1
  end
end

count_friends.html.erb

You have <%=@count%> friends

Woopty doo! You have a working facebook app using Ruby on Rails and Facebooker.

Now if you try to send this to your friends it will not work, because of some changes in the facebook api that were not changed in Facebooker. The main problem lies in the install_url. When your friend tries to install the facebook app, it will send them to your website (no iFrame, just your site outside facebook..no good), instead of directing them to your canvas page which contains your website in an iFrame. To fix this I just hardcoded :canvas=>”true” in this method:

starting at line #189 in vendor/plugins/facebooker/lib/facebooker/rails/controller.rb. I commented out one line and hard coded in a value for canvas. Not sure if this breaks anything else, but it seems fine so far. I am guessing facebook changed something with the fb_sig_in_cavas parameter.

      def create_new_facebook_session_and_redirect!
        session[:facebook_session] = new_facebook_session
        next_url = after_facebook_login_url || default_after_facebook_login_url
        #top_redirect_to session[:facebook_session].login_url({:next => next_url, :canvas=>params[:fb_sig_in_canvas]}) unless @installation_required
        top_redirect_to session[:facebook_session].login_url({:next => next_url, :canvas=>"true"}) unless @installation_required
        false
      end

Push this change to your server and restart your app and this should make everything show up in the iframe after the facebook user installs your app.

On a side note: if you try to use “ensure_application_is_installed_by_facebook_user” in your controller, instead of “ensure_authenticated_to_facebook”, you will get the opposite effect when you click on a link within your application. It will turn into an infinite iframe loop. Every time you click it will create another page inside the iFrame