Tutorial: a simple act_as plugin for ruby on rails

Acts_as_commentable, acts_as_flaggable, acts_as… it seems that this kind of plug-ins is popping out from everywhere, so in this tutorial I’ll try to explain how to get your personal act_as plugin.

Chapter 1: Theory of an act_as

The key-word for a plug-in of this kind is ‘mixing’; mixing means using Modules nested inside Classes. In details this is how an acts_as plugin works:

  • inject into your Activerecord::Base class the module containing the function named ‘act_as_* ’
  • put your ‘act_as_* ’ into your target model
  • in the ‘act_as_* ’ function include the module that contains the instance functions and extend the module with the class functions

Ok, it seems easy, let’s try it out.

Chapter 2: Practice time

In few steps, we’re going to create a very easy act_as plugin: act_as_random. Our aim is to provide a random method that returns a random row from the choosen model. First, let’s create a rails application:

rails myactas

Now we’re ready to create our plugin:

ruby script/generate plugin act_as_random

We’re just 2 steps far from the end, the next one is open /vendor/plugins/act_as_random/lib/act_as_random.rb and put this code inside:

module MyMod

module Acts

module Roled

# included is called from the ActiveRecord::Base

# when you inject this module

def self.included(base)

# Add acts_as_roled availability by extending the module

# that owns the function.

base.extend AddActsAsMethod

end

# this module stores the main function and the two modules for

# the instance and class functions

module AddActsAsMethod

def acts_as_random(options = {})

# Here you can put additional association for the

# target class.

# belongs_to :role

# add class and istance methods

class_eval <<-END

include MyMod::Acts::Roled::InstanceMethods

END

end

end

# Istance methods

module InstanceMethods

# doing this our target class

# acquire all the methods inside ClassMethods module

# as class methods.

def self.included(aClass)

aClass.extend ClassMethods

end

module ClassMethods

# Class methods

# Our random function.

def random

find(:first,order=>"RAND()");

end

end

end

end

end

end

The last step involving our plugin is injecting our module inside ActiveRecord::Base, to achieve this just put this code inside our init.rb (in the plugins/myactas directory):

require ‘acts_as_random’

ActiveRecord::Base.send(:include, MyMod::Acts::Roled)

Done! Now we’re ready to use our new shiny plugin!

Chapter 3: Riding our plugin

Create a test model inside our app:

ruby script/generate model country

then fill our test model with some data using this sql file: countries.sql (i know, no migration and no yaml but it is just because is a test model :P ).

Now open app/models/country.rb and write:

# this is just because our table primary key name

# is not ‘id’

self.primary_key = "Code"

acts_as_random

In order to test this thing works, let’s open the console:

ruby script/console

>> puts "Today destination: " + Country.random.Name + " !!"

"Today destination: Netherlands !!"

=> nil

Leave a Comment

*