Last Update: Wed Dec 03 17:55:43 -0600 2008


Rails plugin to allow for extensible models, where inter-model relations are inferred from the database‘s structure, and not necessarily from explicit declarations in the models.

This means, when one of your models acts_as_magic_model, this plugin will try to infer all the basic relations (has_many, belongs_to and has_and_belongs_to_many) its base table has with other tables in the database, adapting the model correspondingly.

Installing the plugin

The easiest way is through Rails’ own +scripts/plugins+ utility. The first thing you should do is to tell Rails where the plugin‘s tree is located.

If you want to follow the latest changes, you will probably prefer following the project‘s trunk, however, for production, I strongly suggest you to stick to a stable release. Depending on what you prefer, from your project‘s base directory, type:

  $ ./script/plugin source

Or, to follow a given release (say, 0.2 - Of course, check on the latest stable release before doing this):

  $ ./script/plugin source

Then, ask Rails to install the plugin:

  $ ./script/plugin install acts_as_magic_model

If you use Subversion for tracking your project‘s development, you will probably want to mark the plugin as an external repository. To do so, add the -x switch:

  $ ./script/plugin install -x acts_as_magic_model

Using the plugin

In order to use this plugin, you only have to declare it in your model. As an example, say you have the proverbial project-management system, where you have projects (each of which can be of several different types) and people, and a HABTM relation between people and projects. So, you have the following tables (expressed as migrations here):

    create_table :people, :force => true do |t|
      t.column :name, :string

    create_table :project_types, :force => true do |t|
      t.column :name, :string

    create_table :projects, :force => true do |t|
      t.column :name, :string
      t.column :project_type_id, :integer

    create_table :people_projects, :force => true, :id => false do |t|
      t.column :person_id, :integer
      t.column :project_id, :integer

Using acts_as_magic_model, you can skip declaring the relations in your models, like this: (of course, each of the classes still has to be declared in its own file)

    class Person < ActiveRecord::Base

    class Project < ActiveRecord::Base

    class ProjectType < ActiveRecord::Base

And the gaps will be filled in for you - that is, you can go on and ask for Project.find(:first).people, ProjectType.find(:first).projects.size, Person.find(:first) {|pr| pr.project_type}, and whatever you fancy.

Dynamically created models

If any table is related to the models you are declaring as magic does not have a corresponding model explicitly declared, an empty one will be generated - That is, if you create a new table:

  create_table :items, :force => true do |t|
    t.column :name, :string
    t.column :description, :string

  add_column :people, :item_id

When you call Person for the first time, it will create a Item model, just as if you had declared it like:

  class Item < ActiveRecord::Base
    has_many :people

But keep in mind that Item will not exist before Person is first touched.


  • Add the ability to specify whether to auto-declare missing classes or just skip them
  • Allow to be called globally, auto-declaring /all/ of the tables as classes with acts_as_magic_model - would be great for prototyping at least! (i.e. called from environment.rb?)
  • Find some basic constraints and auto-declare validations

Author, copyright and licensing.

This plugin was written by Gunnar Wolf <>, Instituto de Investigaciones Económicas, UNAM.

Licensing information

This plugin is under a MIT license. For further information, please check the LICENSE file.

Getting the code

The plugin project‘s home page can be found at

The Git tree can be cloned anonymously:

    git clone git://

You can also browse the Git repository via the web interface, and even generate tarballs for specific points in time at:;a=tree