Some Rails plugins: acts_as_magic_model

Submitted by gwolf on Sun, 04/13/2008 - 11:52

This is the third plugin I have been working on for Rails - It's the one that still needs most work to be fully usable (for what I originally envisioned it), but is almost there - I have not touched it (nor the other two I recently presented here, acts_as_catalog and Real FK because real-life has demanded my time on various other fronts.
Anyway, this is IMHO the most interesting of the three plugins I've written so far.
So, following what I did with the other plugins: You can go to acts_as_magic_model's main page, or jump straight to its SVN repo. And the basic description follows:
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.

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

  1. create_table :people, :force => true do |t|
  2. t.column :name, :string
  3. end
  4.  
  5. create_table :project_types, :force => true do |t|
  6. t.column :name, :string
  7. end
  8.  
  9. create_table :projects, :force => true do |t|
  10. t.column :name, :string
  11. t.column :project_type_id, :integer
  12. end
  13.  
  14. create_table :people_projects, :force => true, :id => false do |t|
  15. t.column :person_id, :integer
  16. t.column :project_id, :integer
  17. end

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)
  1. class Person < ActiveRecord::Base
  2. acts_as_magic_model
  3. end
  4.  
  5. class Project < ActiveRecord::Base
  6. acts_as_magic_model
  7. end
  8.  
  9. class ProjectType < ActiveRecord::Base
  10. acts_as_magic_model
  11. end

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).projects.map {|pr| pr.project_type}, and whatever you fancy.
In future versions of the plugin, I expect even to get rid to explicitly declare the class declarations.
Of course, you should be warned: Initializing a model using this plugin is quite database-intensive. It will clutter your logs, and it might be unbearable if you use it in development mode. Still, its convenience is very often worth it.
Its main uses should be when prototyping and when designing a system that needs to be flexible to the data models themselves - If you don't expect your system's data structures to be highly malleable, you should probably use acts_as_magic_model only as a prototyping aid.

( categories: )
toupeira's picture

Umm...

Are you aware of Dr. Nic's Magic Models plugin, which also infers validation rules, and actually even lets you skip defining any models *at all*? Now that's magic ;)

admin's picture

They look quite nice, at least from the description

I do not like over-magicizing too many things ;-) But yes, he went on quite a similar direction to mine. Thanks!