Skip to content
jgaskins edited this page Jan 17, 2013 · 1 revision

Declaring Object Mappers

Mappers are generated by the following structure

Perpetuity.generate_mapper_for MyClass do
  # individual mapper configuration goes here
end

This creates a mapper class that defines the way mappers for MyClass should behave. If you prefer, you can create this class yourself.

class MyClassMapper < Perpetuity::Mapper
  map MyClass
end

When doing it this way, the map MyClass line must be there. This tells the mapper class to register itself with Perpetuity as a mapper for MyClass.

Declaring attributes

When persisting object state, we must know which instance variables we will be persisting. In order to declare that, we use the attribute macro. For example:

Perpetuity.generate_mapper_for Article do
  attribute :title
  attribute :body
end

Referenced vs Embedded Attributes

Some databases support complex fields. For example, MongoDB allows any JSON objects, so we can embed objects within other objects. To let the mapper know that we would like to store particular attributes that way, we use the embedded option.

Perpetuity.generate_mapper_for Article do
  attribute :comments, embedded: true
end

If we do not declare attributes to be embedded and the database cannot serialize them innately, Perpetuity will store a reference (containing its class and ID) in the currently serialized object. This allows us to use any object that can be serialized by your database or for which we have a mapper.

Declaring a Specific ID

Sometimes, we would like object IDs to be stored as something other than what the DB thinks they should be. In order to do this, we use the id macro.

Perpetuity.generate_mapper_for Article do
  id { title.gsub(/W+/, '-') }
end

The block is evaluated within the context of the object (in this case, an Article), which means that we have access to all instance variables and private methods within that particular object, which lets us get at any data we need to form a descriptive ID field. NOTE: Whether this is a good idea or not, I am not sure, but it works for now.

Indexes

Indexing is important for database performance. If you use a particular attribute often in your queries (whether as criteria for selecting or sorting), you should consider adding an index for it. We can declare indexes with the index macro:

Perpetuity.generate_mapper_for Article do
  attribute :title

  index :title
end

This does not immediately enforce an index on the database, though, since that can cause downtime for your app. It is best to choose to run things like that in a rake task. We can enforce that index with the reindex! method:

Perpetuity[Article].reindex!

This will ensure that all of your indexes are performed on the database collection.

Talking to Mapper Objects

Accessing mappers after they have been generated is done through the use of the subscript operator on the Perpetuity namespace. For example, if you generate a mapper class for the Article class, you can reach an instance of it by calling Perpetuity[Article].

Perpetuity[Article].insert article

In a Rails controller, a good practice is to memoize this so your code is not littered with Perpetuity[MyClass]:

class ArticlesController < ApplicationController
  def index
    @articles = mapper.all
  end

  private

  def mapper
    @mapper ||= Perpetuity[Article]
  end
end