Properties

A model’s properties are not introspected from the fields in the data-store; In fact the reverse happens. You declare the properties for a model inside it’s class definition, which is then used to generate the fields in the data-store.

This has a few advantages. First it means that a model’s properties are documented in the model itself, not a migration or XML file. If you’ve ever been annoyed at having to look in a schema file to see the list of properties and types for a model, you’ll find this particularly useful. There’s no need for a special annotate rake task either.

Second, it lets you limit access to properties using Ruby’s access semantics. Properties can be declared public, private or protected. They are public by default.

Finally, since DataMapper only cares about properties explicitly defined in your models, DataMapper plays well with legacy data-stores and shares them easily with other applications.

Declaring Properties

Inside your class, call the property method for each property you want to add. The only two required arguments are the name and type, everything else is optional.

1 class Post 
2   include DataMapper::Resource
3   property :id,         Integer,    :serial => true    # primary serial key
4   property :title,      String,     :nullable => false # Cannot be null
5   property :published,  Boolean,    :default  => false # Default value for new records is false
6 end

Available Types

DM-Core supports the following ‘primitive’ data-types.

If you include DM-More’s DM-Types, the following data-types are supported:

Limiting Access

Access for properties is defined using the same semantics as Ruby. Accessors are public by default, but you can declare them as private or protected if you need. You can set access using the :accessor option. For demonstration, we’ll reopen our Post class.

1 class Post 
2   property :title,  :string, :accessor => :private   # Both reader and writer are private
3   property :body,   :text,   :accessor => :protected # Both reader and writer are protected
4 end

You also have more fine grained control over how you declare access. You can, for example, have a public reader and private writer by using the :writer and :reader options. (Remember, the default is Public)

1 class Post
2   property :title, String, :writer => :private    # Only writer is private
3   property :tags,  String, :reader => :protected  # Only reader is protected
4 end

Over-riding Accessors

When a property has declared accessors for getting and setting, it’s values are added to the model. Just like using attr_accessor, you can over-ride these with your own custom accessors. It’s a simple matter of adding an accessor after the property declaration. Reopening the Post class….

 1 class Post 
 2   property :slug,  String
 3   
 4   def slug=(new_slug)
 5     raise ArgumentError if new_slug != 'DataMapper is Awesome'
 6     attribute_set(:slug, new_title)   # use attribute_set instead of talking to the @ivars directly.  
 7                                       # This tracks dirtiness.
 8   end
 9 end

Lazy Loading

Properties can be configured to be lazy loading. A lazily loaded property is not requested from the data-store by default. Instead it is only loaded when it’s accessor is called for the first time. This means you can stop default queries from being greedy, a particular problem with text fields. Text fields are lazily loaded by default, which you can over-ride if you need to.

1 class Post
2   include DataMapper::Resource
3   property :id,     Integer,  :serial => true
4   property :title,  String                 
5   property :body,   Text                        # Is lazily loaded by default
6   property :notes,  Text,     :lazy => false    # Isn't lazily loaded
7 end

Primary Keys, Natural Keys, and Composite Keys


Important Change

Primary keys are not automatically created for you, as with previous versions

of DataMapper or ActiveRecord. You MUST configure at least one key property on

your data-store.

To set your own primary key, and even use a string column as a primary ‘natural’ key, pass :key => true as an option.

1 class Post 
2   include DataMapper::Resource
3   property :slug,  String, :key => true
4 end

To use a composite key of any length, simply create more than one property with the :key => true as an option.

1 class Post
2   include DataMapper::Resource
3   property :old_id, Integer, :key => true
4   property :new_id, Integer, :key => true