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 ).
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