Rails: macro style functions

Chris's answer is right. But here's where you want to throw your code to write your own:

The easiest way to add Controller methods like that is to define it in ApplicationController:

class ApplicationController < ActionController::Base
  ...
  def self.acts_as_awesome
    do_awesome_things
  end
end

Then you can access it from individual controllers like so:

class AwesomeController < ApplicationController
  acts_as_awesome
end

For models, you want to reopen ActiveRecord::Base:

module ActiveRecord
  class Base
    def self.acts_as_super_awesome
      do_more_awesome_stuff
    end
  end
end

I personally would put that in a file in config/initializers so that it gets loaded once, and so that I know where to look for it always.

Then you can access it in models like so:

class MySuperAwesomeModel < ActiveRecord::Base
  acts_as_super_awesome
end

They're just standard Ruby functions. Ruby's flexible approach to syntax makes it look better than it is. You can create your own simply by writing your method as a normal Ruby function and doing one of the following:

  1. putting it somewhere that's accessible by your controllers such as application.rb

  2. putting it in a file and requiring it in.

  3. mixing the code into a class via the Ruby include keyword.


That last option is great for model classes and the first option is really only for controllers.

An Example


An example of the first approach is shown below. In this example we add code into the ApplicationController class (in application.rb) and use it in the other controllers.

class BusinessEntitiesController < ApplicationController

    nested_within :Glossary

    private

        #  Standard controller code here ....

The nested_within provides helper functions and variables to help identify the id of the "parent" resource. In effect it parses the URL on the fly and is accessible by every one of our controllers. For example when a request comes into the controller, it is automatically parsed and the class attribute @parent_resource is set to the result of a Rails find. A side effect is that a "Not Found" response is sent back if the parent resource doesn't exist. That saves us from typing boiler plate code in every nested resource.

That all sounds pretty clever but it is just a standard Ruby function at heart ...


    def self.nested_within(resource)
        #
        #   Add a filter to the about-to-be-created method find_parent_id
        #
        before_filter :find_parent_id
    
        #
        #   Work out what the names of things
        #
        resource_name = "#{resource.to_s.tableize.singularize}"
        resource_id = "#{resource_name}_id"
        resource_path = "#{resource.to_s.tableize}_path"
    
        #
        #   Get a reference to the find method in the model layer
        #
        finder = instance_eval("#{resource}.method :find_#{resource_name}")
    
    
        #
        #   Create a new method which gets executed by the before_filter above
        #
        define_method(:find_parent_id) do
            @parent_resource = finder.call(params[resource_id])
    
            head :status => :not_found, :location => resource_path 
                    unless @parent_resource
        end
    end

The nested_within function is defined in ApplicationController (controllers/application.rb) and therefore gets pulled in automatically.

Note that nested_within gets executed inside the body of the controller class. This adds the method find_parent_id to the controller.


Summary

A combination of Ruby's flexible syntax and Rail's convention-over-configuration makes this all look more powerful (or weirder) than it actually is.

Next time you find a cool method, just stick a breakpoint in front of it and trace through it. Ahh Open Source!

Let me know if I can help further or if you want some pointers on how that nested_within code works.

Chris