Rails 3 is_documentable with activeadmin

I need to add the chance to add as many documents as needed for several models of a Rails 3 app.

Each model is something that can have associated drawings, administrative acts and so forth.

To avoid duplication as far as possible I opted for an acts_as like feature for documents.

It will be called acts as documentable.

The acts as coding pattern rely on the polymorphic association with which a model can belong to more than one other model, on a single association.

Let’s see what this means.

Let’s imagine we have three models: User, Project and Tasks.

We want each model to be able to store n documents uploaded by a user.

With a polymorphic association we can obtain this result with the following Rails code:

The polymorphic reference in the migration automatically creates two columns:

  • documentable_id: the id of the object to which the document will be added
  • documentable_type: the class name of the object to which the document will be added

In this way Rails will be able to add n documents to each model which will be documentable.

We thus need a way to extend each model with the Documentable module.

This is achieved extending ActiveRecord::Base and is the standard way of structuring a gem extension for ActiveRecord.

Here is the structure:

The documentable.rb file should be saved in the lib folder.

In Rails 3 because of the assets pipeline files included in the lib folder are no longer loaded by default.

You both need to explicitly load files in the lib AND require them! I know it sounds strange but it0s the only way I managed to extend ActiveRecord with my Documentable module.

Now I can extend my models with the is_documentable class method and let them be able to have many documents:

Now let’s throw in a couple more things:

  • dragonfly to upload files
  • activeadmin to manage documents

For dragonfly nothing interesting, just follow the rails 3 quick start guide and use the file_accessor instead of the image_accessor.

Something more interesting for activeadmin. Here you can add a nested form for your documents using the wonderful has_many form method:

What this code does is simply to add a nested form for documents with buttons to add and remove each document!

If you want some more info on the has_many method check this page on active_admin.

Maybe I’ll set up a gem sometime.