Module: DataMapper::Resource

Extended by:
Chainable, Deprecate
Includes:
Extlib::Assertions
Defined in:
lib/dm-core/resource.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Chainable

chainable, extendable

Methods included from Deprecate

deprecate

Instance Attribute Details

#collectionCollection, FalseClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Gets a Collection with the current Resource instance as its only member

Returns:

  • (Collection, FalseClass)

    nil if this is a new record, otherwise a Collection with self as its only member



607
608
609
610
# File 'lib/dm-core/resource.rb', line 607

def collection
  return @collection if @collection || new? || frozen?
  @collection = Collection.new(query, [ self ])
end

Class Method Details

.append_inclusions(*inclusions) ⇒ Object

Deprecated.


10
11
12
13
# File 'lib/dm-core/resource.rb', line 10

def self.append_inclusions(*inclusions)
  warn "DataMapper::Resource.append_inclusions is deprecated, use DataMapper::Model.append_inclusions instead (#{caller[0]})"
  Model.append_inclusions(*inclusions)
end

.descendantsObject

Deprecated.


22
23
24
25
# File 'lib/dm-core/resource.rb', line 22

def self.descendants
  warn "DataMapper::Resource.descendants is deprecated, use DataMapper::Model.descendants instead (#{caller[0]})"
  Model.descendants
end

.extra_inclusionsObject

Deprecated.


16
17
18
19
# File 'lib/dm-core/resource.rb', line 16

def self.extra_inclusions
  warn "DataMapper::Resource.extra_inclusions is deprecated, use DataMapper::Model.extra_inclusions instead (#{caller[0]})"
  Model.extra_inclusions
end

.included(model) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Makes sure a class gets all the methods when it includes Resource



49
50
51
# File 'lib/dm-core/resource.rb', line 49

def self.included(model)
  model.extend Model
end

Instance Method Details

#<=>(other) ⇒ Integer

Compares two Resources to allow them to be sorted

Parameters:

  • other (Resource)

    The other Resource to compare with

Returns:

  • (Integer)

    Return 0 if Resources should be sorted as the same, -1 if the other Resource should be after self, and 1 if the other Resource should be before self



435
436
437
438
439
440
441
442
443
444
445
# File 'lib/dm-core/resource.rb', line 435

def <=>(other)
  unless other.kind_of?(model.base_model)
    raise ArgumentError, "Cannot compare a #{other.model} instance with a #{model} instance"
  end
  cmp = 0
  model.default_order(repository_name).each do |direction|
    cmp = direction.get(self) <=> direction.get(other)
    break if cmp != 0
  end
  cmp
end

#==(other) ⇒ Boolean

Compares another Resource for equivalency

Resource is equal to other if they are the same object (identity) or if they are both of the *same base model* and all of their attributes are equivalent

Parameters:

  • other (Resource)

    the other Resource to compare with

Returns:

  • (Boolean)

    true if they are equivalent, false if not



417
418
419
420
421
422
# File 'lib/dm-core/resource.rb', line 417

def ==(other)
  return true if equal?(other)
  other.respond_to?(:model)                       &&
  model.base_model.equal?(other.model.base_model) &&
  cmp?(other, :==)
end

#attribute_dirty?(name) ⇒ Boolean

Checks if an attribute has unsaved changes

Parameters:

  • name (Symbol)

    name of attribute to check for unsaved changes

Returns:

  • (Boolean)

    true if attribute has unsaved changes



526
527
528
# File 'lib/dm-core/resource.rb', line 526

def attribute_dirty?(name)
  dirty_attributes.key?(properties[name])
end

#attribute_get(name) ⇒ Object Also known as: []

Returns the value of the attribute.

Do not read from instance variables directly, but use this method. This method handles lazy loading the attribute and returning of defaults if nessesary.

Examples:

class Foo
  include DataMapper::Resource

  property :first_name, String
  property :last_name,  String

  def full_name
    "#{attribute_get(:first_name)} #{attribute_get(:last_name)}"
  end

  # using the shorter syntax
  def name_for_address_book
    "#{last_name}, #{first_name}"
  end
end

Parameters:

  • name (Symbol)

    name of attribute to retrieve

Returns:

  • (Object)

    the value stored at that given attribute (nil if none, and default if necessary)



188
189
190
# File 'lib/dm-core/resource.rb', line 188

def attribute_get(name)
  properties[name].get(self)
end

#attribute_loaded?(name) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Checks if an attribute has been loaded from the repository

Examples:

class Foo
  include DataMapper::Resource

  property :name,        String
  property :description, Text,   :lazy => false
end

Foo.new.attribute_loaded?(:description)   #=> false

Returns:

  • (Boolean)

    true if ivar name has been loaded

  • (Boolean)

    true if ivar name has been loaded



513
514
515
# File 'lib/dm-core/resource.rb', line 513

def attribute_loaded?(name)
  properties[name].loaded?(self)
end

#attribute_set(name, value) ⇒ Object Also known as: []=

Sets the value of the attribute and marks the attribute as dirty if it has been changed so that it may be saved. Do not set from instance variables directly, but use this method. This method handles the lazy loading the property and returning of defaults if nessesary.

Examples:

class Foo
  include DataMapper::Resource

  property :first_name, String
  property :last_name,  String

  def full_name(name)
    name = name.split(' ')
    attribute_set(:first_name, name[0])
    attribute_set(:last_name, name[1])
  end

  # using the shorter syntax
  def name_from_address_book(name)
    name = name.split(', ')
    first_name = name[1]
    last_name = name[0]
  end
end

Parameters:

  • name (Symbol)

    name of attribute to set

  • value (Object)

    value to store

Returns:

  • (Object)

    the value stored at that given attribute, nil if none, and default if necessary



231
232
233
# File 'lib/dm-core/resource.rb', line 231

def attribute_set(name, value)
  properties[name].set(self, value)
end

#attributes(key_on = :name) ⇒ Hash

Gets all the attributes of the Resource instance

Parameters:

  • key_on (Symbol) (defaults to: :name)

    Use this attribute of the Property as keys. defaults to :name. :field is useful for adapters :property or nil use the actual Property object.

Returns:

  • (Hash)

    All the attributes



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/dm-core/resource.rb', line 248

def attributes(key_on = :name)
  attributes = {}
  properties.each do |property|
    if model.public_method_defined?(name = property.name)
      key = case key_on
        when :name  then name
        when :field then property.field
        else             property
      end

      attributes[key] = send(name)
    end
  end
  attributes
end

#attributes=(attributes) ⇒ Hash

Assign values to multiple attributes in one call (mass assignment)

Parameters:

  • attributes (Hash)

    names and values of attributes to assign

Returns:

  • (Hash)

    names and values of attributes assigned



273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/dm-core/resource.rb', line 273

def attributes=(attributes)
  attributes.each do |name, value|
    case name
      when String, Symbol
        if model.public_method_defined?(setter = "#{name}=")
          send(setter, value)
        else
          raise ArgumentError, "The attribute '#{name}' is not accessible in #{model}"
        end
      when Associations::Relationship, Property
        name.set(self, value)
    end
  end
end

#clean?Boolean

Checks if the resource has no changes to save

Returns:

  • (Boolean)

    true if the resource may not be persisted



137
138
139
# File 'lib/dm-core/resource.rb', line 137

def clean?
  !dirty?
end

#destroy!Boolean

Destroy the instance, remove it from the repository, bypassing hooks

Returns:

  • (Boolean)

    true if resource was destroyed



375
376
377
378
379
380
381
382
383
384
# File 'lib/dm-core/resource.rb', line 375

def destroy!
  if saved? && repository.delete(Collection.new(query, [ self ])) == 1
    @destroyed = true
    @collection.delete(self) if @collection
    reset
    freeze
  end

  destroyed?
end

#destroyed?Boolean

Checks if this Resource instance is destroyed

Returns:

  • (Boolean)

    true if the resource has been destroyed



127
128
129
# File 'lib/dm-core/resource.rb', line 127

def destroyed?
  @destroyed == true
end

#dirty?Boolean

Checks if the resource has unsaved changes

Returns:

  • (Boolean)

    true if resource may be persisted



147
148
149
150
151
152
153
154
155
# File 'lib/dm-core/resource.rb', line 147

def dirty?
  if original_attributes.any?
    true
  elsif new?
    model.serial || properties.any? { |property| property.default? }
  else
    false
  end
end

#dirty_attributesHash

Hash of attributes that have unsaved changes

Returns:

  • (Hash)

    attributes that have unsaved changes



536
537
538
539
540
541
542
543
544
# File 'lib/dm-core/resource.rb', line 536

def dirty_attributes
  dirty_attributes = {}

  original_attributes.each_key do |property|
    dirty_attributes[property] = property.value(property.get!(self))
  end

  dirty_attributes
end

#eql?(other) ⇒ Boolean

Compares another Resource for equality

Resource is equal to other if they are the same object (identity) or if they are both of the *same model* and all of their attributes are equivalent

Parameters:

  • other (Resource)

    the other Resource to compare with

Returns:

  • (Boolean)

    true if they are equal, false if not



399
400
401
402
# File 'lib/dm-core/resource.rb', line 399

def eql?(other)
  return true if equal?(other)
  instance_of?(other.class) && cmp?(other, :eql?)
end

#hashObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns hash value of the object. Two objects with the same hash value assumed equal (using eql? method)

DataMapper resources are equal when their models have the same hash and they have the same set of properties

When used as key in a Hash or Hash subclass, objects are compared by eql? and thus hash value has direct effect on lookup



457
458
459
# File 'lib/dm-core/resource.rb', line 457

def hash
  key.hash
end

#inspectString

Get a Human-readable representation of this Resource instance

Foo.new   #=> #<Foo name=nil updated_at=nil created_at=nil id=nil>

Returns:

  • (String)

    Human-readable representation of this Resource instance



469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/dm-core/resource.rb', line 469

def inspect
  # TODO: display relationship values
  attrs = properties.map do |property|
    value = if new? || property.loaded?(self)
      property.get!(self).inspect
    else
      '<not loaded>'
    end

    "#{property.instance_variable_name}=#{value}"
  end

  "#<#{model.name} #{attrs.join(' ')}>"
end

#keyArray(Key)

Retrieve the key(s) for this resource.

This always returns the persisted key value, even if the key is changed and not yet persisted. This is done so all relations still work.

Returns:

  • (Array(Key))

    the key(s) identifying this resource



86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/dm-core/resource.rb', line 86

def key
  return @key if defined?(@key)

  key = model.key(repository_name).map do |property|
    original_attributes[property] || (property.loaded?(self) ? property.get!(self) : nil)
  end

  return unless key.all?

  # memoize the key if the Resource is not frozen
  @key = key unless frozen?

  key
end

#new?Boolean

Checks if this Resource instance is new

Returns:

  • (Boolean)

    true if the resource is new and not saved



107
108
109
# File 'lib/dm-core/resource.rb', line 107

def new?
  !saved?
end

#original_attributesHash

Hash of original values of attributes that have unsaved changes

Returns:

  • (Hash)

    original values of attributes that have unsaved changes



490
491
492
# File 'lib/dm-core/resource.rb', line 490

def original_attributes
  @original_attributes ||= {}
end

#reloadResource

Reloads association and all child association

Returns:

  • (Resource)

    the receiver, the current Resource instance



294
295
296
297
298
299
300
301
# File 'lib/dm-core/resource.rb', line 294

def reload
  if saved?
    eager_load(loaded_properties)
    child_relationships.each { |relationship| relationship.get!(self).reload }
  end

  self
end

#repositoryRepository

Repository this resource belongs to in the context of this collection or of the resource’s class.

Returns:

  • (Repository)

    the respository this resource belongs to, in the context of a collection OR in the instance’s Model’s context



71
72
73
74
# File 'lib/dm-core/resource.rb', line 71

def repository
  # only set @repository explicitly when persisted
  defined?(@repository) ? @repository : model.repository
end

#resetObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Reset the Resource to a similar state as a new record: removes it from identity map and clears original property values (thus making all properties non dirty)



593
594
595
596
597
598
# File 'lib/dm-core/resource.rb', line 593

def reset
  @saved = false
  identity_map.delete(key)
  original_attributes.clear
  self
end

#save!Boolean

Save the instance and loaded, dirty associations to the data-store, bypassing hooks

Returns:

  • (Boolean)

    true if Resource instance and all associations were saved



353
354
355
# File 'lib/dm-core/resource.rb', line 353

def save!
  save_parents(false) && save_self(false) && save_children(false)
end

#save_children(safe = true) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Saves the children resources

Returns:

  • (Boolean)

    true if the children were successfully saved



581
582
583
584
585
586
# File 'lib/dm-core/resource.rb', line 581

def save_children(safe = true)
  child_relationships.all? do |relationship|
    association = relationship.get!(self)
    safe ? association.save : association.save!
  end
end

#save_parents(safe = true) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Saves the parent resources

Returns:

  • (Boolean)

    true if the parents were successfully saved



566
567
568
569
570
571
572
573
# File 'lib/dm-core/resource.rb', line 566

def save_parents(safe = true)
  parent_relationships.all? do |relationship|
    parent = relationship.get!(self)
    if parent.dirty? ? parent.save_parents(safe) && parent.save_self(safe) : parent.saved?
      relationship.set(self, parent)  # set the FK values
    end
  end
end

#save_self(safe = true) ⇒ Boolean

Saves the resource

Returns:

  • (Boolean)

    true if the resource was successfully saved



552
553
554
555
556
557
558
# File 'lib/dm-core/resource.rb', line 552

def save_self(safe = true)
  if safe
    new? ? create_hook : update_hook
  else
    new? ? _create : _update
  end
end

#saved?Boolean

Checks if this Resource instance is saved

Returns:

  • (Boolean)

    true if the resource has been saved



117
118
119
# File 'lib/dm-core/resource.rb', line 117

def saved?
  @saved == true
end

#update!(attributes = {}) ⇒ Boolean

Updates attributes and saves this Resource instance, bypassing hooks

Parameters:

  • attributes (Hash) (defaults to: {})

    attributes to be updated

Returns:

  • (Boolean)

    true if resource and storage state match



329
330
331
332
333
# File 'lib/dm-core/resource.rb', line 329

def update!(attributes = {})
  assert_update_clean_only(:update!)
  self.attributes = attributes
  save!
end

#update_attributes(attributes = {}, *allowed) ⇒ Object

Deprecated.

Deprecated API for updating attributes and saving Resource

See Also:

  • #update


32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/dm-core/resource.rb', line 32

def update_attributes(attributes = {}, *allowed)
  assert_update_clean_only(:update_attributes)

  warn "#{model}#update_attributes is deprecated, use #{model}#update instead (#{caller[0]})"

  if allowed.any?
    warn "specifying allowed in #{model}#update_attributes is deprecated, " \
      "use Hash#only to filter the attributes in the caller (#{caller[0]})"
    attributes = attributes.only(*allowed)
  end

  update(attributes)
end