Index

Centralized Associations in Rails

Normally, the association declarations are spread all over the model files:

class User < ActiveRecord::Base
  has_and_belongs_to_many :roles
  has_many :freeboxes, :order => 'name'
  # ...
end

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users
  # ...
end

class Freebox < ActiveRecord::Base
  belongs_to :user
  # ...
end

This is OK, but when there are many models, it might be more convenient to maintain and see all associations in one place. Here's one way to do this:

lib/associations.rb:
module Associations
  def self.included(klass)
    klass.class_eval do
      case klass.name
      when 'User'
        has_and_belongs_to_many :roles
        has_many :freeboxes, :order => 'name'
      when 'Role'
        has_and_belongs_to_many :users
      when 'Freebox'
        belongs_to :user
      end
    end
  end
end
From ruby-doc.org/core/classes/Module.html:
included(othermod)
Callback invoked whenever the receiver is included in another module or class. This should be used [...] if your code wants to perform some action when a module is included in another.
mod.class_eval
Evaluates the string or block in the context of mod.

In each of the model files, I replaced all association declarations with one line:

class User < ActiveRecord::Base
  include Associations
  # ...
end

class Role < ActiveRecord::Base
  include Associations
  # ...
end

class Freebox < ActiveRecord::Base
  include Associations
  # ...
end

So whenever include Associations is called from a class, the block after klass.class_eval is called, which declares the corresponding association(s) for that class.