6 July 2009 · About 2 minutes read

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:

```ruby# app/models/event.rb

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.

bashscript/generate rspec_controller events index

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:

```ruby# config/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/]

Chris Blunt
Chris Blunt @cblunt
Chris is the founder of Plymouth Software. As well as code and business, he enjoys being a Dad, swimming, and the fine art of drinking tea.