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



597
598
599
600
# File 'lib/dm-core/resource.rb', line 597

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



425
426
427
428
429
430
431
432
433
434
435
# File 'lib/dm-core/resource.rb', line 425

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



407
408
409
410
411
412
# File 'lib/dm-core/resource.rb', line 407

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



516
517
518
# File 'lib/dm-core/resource.rb', line 516

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)



178
179
180
# File 'lib/dm-core/resource.rb', line 178

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



503
504
505
# File 'lib/dm-core/resource.rb', line 503

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



221
222
223
# File 'lib/dm-core/resource.rb', line 221

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



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/dm-core/resource.rb', line 238

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



263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/dm-core/resource.rb', line 263

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



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

def clean?
  !dirty?
end

#destroy!Boolean

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

Returns:

  • (Boolean)

    true if resource was destroyed



365
366
367
368
369
370
371
372
373
374
# File 'lib/dm-core/resource.rb', line 365

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

#dirty?Boolean

Checks if the resource has unsaved changes

Returns:

  • (Boolean)

    true if resource may be persisted



137
138
139
140
141
142
143
144
145
# File 'lib/dm-core/resource.rb', line 137

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



526
527
528
529
530
531
532
533
534
# File 'lib/dm-core/resource.rb', line 526

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



389
390
391
392
# File 'lib/dm-core/resource.rb', line 389

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



447
448
449
# File 'lib/dm-core/resource.rb', line 447

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



459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/dm-core/resource.rb', line 459

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



480
481
482
# File 'lib/dm-core/resource.rb', line 480

def original_attributes
  @original_attributes ||= {}
end

#reloadResource

Reloads association and all child association

Returns:

  • (Resource)

    the receiver, the current Resource instance



284
285
286
287
288
289
290
291
# File 'lib/dm-core/resource.rb', line 284

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)



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

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



343
344
345
# File 'lib/dm-core/resource.rb', line 343

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



571
572
573
574
575
576
# File 'lib/dm-core/resource.rb', line 571

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



556
557
558
559
560
561
562
563
# File 'lib/dm-core/resource.rb', line 556

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



542
543
544
545
546
547
548
# File 'lib/dm-core/resource.rb', line 542

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



319
320
321
322
323
# File 'lib/dm-core/resource.rb', line 319

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