require 'active_model/naming'

module DataMapper
  module ActiveModel

    module ClassMethods

      # Returns an ActiveModel::Name object for module. It can be
      # used to retrieve all kinds of naming-related information.
      def model_name
        @_model_name ||= ::ActiveModel::Name.new(self)
      end

    end

    module InstanceMethods

      def to_model
        self
      end

      def persisted?
        saved?
      end

      def to_key
        key
      end

      def to_param
        return nil if key.nil?
        if key.length > 1
          raise "You need to implement #to_param yourself to support this key: #{self.class.key.inspect}"
        else
          self.key.first.to_s
        end
      end

      # Define the minimum requirements if the resource
      # has no concept of validation baked in, which
      # happens if dm-validations is not required.
      unless respond_to?(:validatable?)

        def valid?
          true
        end

        def errors
          obj = Object.new
          def obj.[](key)         [] end
          def obj.full_messages() [] end
          obj
        end

      end

    end

  end

  Model.append_extensions(ActiveModel::ClassMethods)
  Model.append_inclusions(ActiveModel::InstanceMethods)

end

require 'active_model/naming'

module DataMapper
  module ActiveModel

    module InstanceMethods

      def to_model
        self
      end

      def persisted?
        saved?
      end

      def to_key
        key
      end

      def to_param
        return nil if key.nil?
        if key.length > 1
          raise "You need to implement #to_param yourself to support this key: #{self.class.key.inspect}"
        else
          self.key.first.to_s
        end
      end

      # Define the minimum requirements if the resource
      # has no concept of validation baked in, which
      # happens if dm-validations is not required.
      unless respond_to?(:validatable?)

        def valid?
          true
        end

        def errors
          obj = Object.new
          def obj.[](key)         [] end
          def obj.full_messages() [] end
          obj
        end

      end

    end

  end

  Model.append_extensions(::ActiveModel::Naming)
  Model.append_inclusions(ActiveModel::InstanceMethods)

end

Use the ActiveModel::Naming module the way it's intended
Use the ActiveModel::Naming module the way it's intended

Technically, for rails compatibility alone, it should
be sufficient to simply provide a .model_name method
for DataMapper::Resource objects. I think that's the
reason why our previous code worked and actually still
works with rails alone.

However, the documented way to take advantage of the
active model naming facilities is to

  extend ActiveModel::Naming

into any objects wanting to be naming compliant with
the ActiveModel interface. The rspec-rails gem relies
on that way of doing things, and expects any ORM object
to be #kind_of?(ActiveModel::Naming) in case you want
to mock it at least (by calling #mock_model for example)

Without this change, a lot of the controller specs
that get generated by something like

  rails generate scaffold Person name:string

failed. Most of them with the following error message:

The mock_model method can only accept as its first argument:
  * A String representing a Class that does not exist
  * A String representing a Class that extends ActiveModel::Naming
  * A Class that extends ActiveModel::Naming

This commit fixes this by making sure that all our
DataMapper::Resource instances actually

  extend ActiveModel::Naming

This means that a freshly scaffolded model, created
with a call like

  rails generate scaffold Person name:string

passes all its generated specs. The only manual
intervention that needs to be done, is to make sure
to call #auto_migrate! at some point before running
the specs. This can easily be done by putting

  config.before(:suite) do
    DataMapper.auto_migrate!
  end

into the configure block inside spec/spec_helper.rb