Rails: Abstract Models - ActiveRecord Without Tables

I recently hit a situation where I needed an ActiveRecord model with no corresponding database table. The model had to represent a collection of other event-type models - for example: Birthdays, Weddings, Anniversaries, etc.

As an Event model would be a completely abstract representation of another model, it didn't make sense to store them in the database. Unfortunately, ActiveRecord doesn't appear to support this natively. Luckily, I came across this post by Micha? Szajbe which demonstrates ActiveRecord model without a corresponding table. I've used Micha?'s code to build the example model below:

Event-Model Example

First, create a class to represent your abstract model using the code from the post above:

class Event < ActiveRecord::Base

  def self.columns

    @columns ||= []

  end

  def self.column(name, sql_type = nil, default = nil, null = true)

    columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)

  end

  # Manually define the columns used by this model

  column :name, :string

  column :event_at, :datetime

  column :description, :string

  column :event_type, :string

end```



(Note that I've since found that ActiveRecord doesn't like any column called `id`)


In my example, I gave each of the real models a `to_event` method to capture the common attributes and return an `Event` model:

ruby# app/models/birthday.rb

def to_event

Event.new(

:name => [self.person.name, "'s birthday"].join,

:event_at self.birthday,

:event_type => 'birthday'

)

end```

Now we can build a normal RESTful controller with index and show actions to display the Events. Note that because the models are just an abstract view on other models, the CRUD RESTful routes (create, edit, etc.) are redundant.

In the controller, build an array of events by calling `to_event` on your other models:

ruby# app/controllers/events_controller.rb

def index

@events = Wedding.find(:all).collect { |w| w.to_event }

@events += Birthdays.find(:all).collect { |b| b.to_event }

end```

Finally, add a RESTful route for your events into routes.rb:

map.resources :events```



Now, the abstract event models can be accessed using the normal RESTful URL:

texthttp://localhost/events```

References

Tableless Models in Rails [Micha? Szajbe, http://codetunes.com/]