Home > Articles > Web Development

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

5.2 Model classes

Model classes exist in the directory app/models. These classes typically have singular names and exist one class per file. Examples that may appear in a Merb blog application are Post in the file app/models/post.rb and FavoriteLink in app/models/favorite_link.rb. Organizing model classes in this way isn’t strictly necessary, though, since Merb by default includes everything inside app/models by recursive glob. In other words, so long as you make sure that your model class is somewhere in app/models, it will be available at boot. Nonetheless, our recommendation is that you do arrange your model classes in a reasonable way, so that both you and others can easily find them.

While various DataMapper modules can incorporate different functionality within your model class, the fundamental module that must be included in order for your class to work with DataMapper is DataMapper::Resource. Below we include this module and effectively set up our User class as a DataMapper model.

class User
  include DataMapper::Resource
end

Let’s take a look at the source behind the Resource module to get a feel for how it affects the class in which it is included:

module DataMapper
  module Resource

    # ...

    # @api public
    def self.append_inclusions(*inclusions)
      extra_inclusions.concat inclusions
      true
    end

    def self.extra_inclusions
      @extra_inclusions ||= []
    end

    # When Resource is included in a class this
    # method makes sure it gets all the methods
    #
    # -
    # @api private
    def self.included(model)
      model.extend Model
      model.extend ClassMethods
        if defined?(ClassMethods)
      model.const_set('Resource', self)
        unless model.const_defined?('Resource')
      extra_inclusions.each { |inclusion|
        model.send(:include, inclusion) }
      descendants << model
      class << model
        @_valid_model = false
        attr_reader :_valid_model
      end
    end

    # ...
  end

end

Focusing on the last method listed above, we can see that the Resource module extends the class in which it is included (above called model). In the process, it principally extends it with the Model module, which contains the logic for property persistence and object retrieval. As we come to these methods later on, we’ll open up the Model class source as well. For now, however, take note of Resource’s ability to include extra modules through the class method append_inclusions. This method is used extensively by DataMapper plugins that need to extend the functionality of all DataMapper models. For instance, below is some of the source for dm-timestamps, which automatically sets timestamps on properties of particular names.

module DataMapper
  module Timestamp
    Resource.append_inclusions self

    # ...

    def self.included(model)
      model.before :create, :set_timestamps
      model.before :update, :set_timestamps
      model.extend ClassMethods
    end

  end

end

The first line appends the module to all DataMapper models. Later on, using its own self.included, the module includes its own logic into the model. This cascading of modules is thus particularly effective for code as modular as DataMapper.

  • + Share This
  • 🔖 Save To Your Account