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.

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.

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