Class: VirtualBox::AbstractModel Abstract

Inherits:
Object
  • Object
show all
Includes:
AbstractModel::Attributable, AbstractModel::Dirty, AbstractModel::Relatable, AbstractModel::Validatable
Defined in:
lib/virtualbox/abstract_model.rb,
lib/virtualbox/abstract_model/dirty.rb,
lib/virtualbox/abstract_model/relatable.rb,
lib/virtualbox/abstract_model/validatable.rb,
lib/virtualbox/abstract_model/attributable.rb

Overview

This class is abstract.

AbstractModel is the base class used for most of virtualbox's classes. It provides convenient ActiveRecord-style model behavior to subclasses.

Direct Known Subclasses

AttachedDevice, ForwardedPort, Global, Image, Media, Nic, SharedFolder, StorageController, USB, VM

Class Method Summary

Instance Method Summary

Methods included from AbstractModel::Attributable

#attributes, #has_attribute?, included, #loaded_attribute?, #read_attribute, #readonly_attribute?

Methods included from AbstractModel::Dirty

#changed?, #changes, #clear_dirty!, #ignore_dirty, #method_missing, #set_dirty!

Methods included from AbstractModel::Relatable

#destroy_relationship, #destroy_relationships, #has_relationship?, included, #loaded_relationship?, #read_relationship, #relationship_data, #save_relationship, #save_relationships

Methods included from AbstractModel::Validatable

#add_error, #clear_errors, #valid?, #validates_presence_of

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class VirtualBox::AbstractModel::Dirty

Class Method Details

+ (Object) reload!



25
26
27
# File 'lib/virtualbox/abstract_model.rb', line 25

def reload!
  @_reload = true
end

+ (Boolean) reload?

Returns whether or not the class should be reloaded.

Returns:

  • (Boolean)


21
22
23
# File 'lib/virtualbox/abstract_model.rb', line 21

def reload?
  !!@_reload
end

+ (Object) reloaded!



29
30
31
# File 'lib/virtualbox/abstract_model.rb', line 29

def reloaded!
  @_reload = false
end

Instance Method Details

- (Object) destroy(*args)

Destroys the model. The exact behaviour of this method is expected to be defined on the subclasses. This method on AbstractModel simply propagates the destroy to the dependent relationships. For more information on relationships, see Relatable.



202
203
204
205
206
207
# File 'lib/virtualbox/abstract_model.rb', line 202

def destroy(*args)
  # Destroy dependent relationships
  self.class.relationships.each do |name, options|
    destroy_relationship(name, *args) if options[:dependent] == :destroy
  end
end

- (Object) errors

Returns the errors for a model.



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/virtualbox/abstract_model.rb', line 66

def errors
  error_hash = super

  self.class.relationships.each do |name, options|
    next unless options && options[:klass].respond_to?(:errors_for_relationship)
    relationship_errors = options[:klass].errors_for_relationship(self, relationship_data[name])

    error_hash.merge!({ :foos => relationship_errors }) if relationship_errors.length > 0
  end

  error_hash
end

- (Object) existing_record!

Explicitly sets the model to not be a new record. If you're using this method outside of virtualbox library core, you should really be asking yourself "why?"



61
62
63
# File 'lib/virtualbox/abstract_model.rb', line 61

def existing_record!
  @new_record = false
end

- (Object) inspect

Creates a human-readable format for this model. This method overrides the default #<class> syntax since this doesn't work well for AbstractModels. Instead, it abbreviates it, instead showing all the attributes and their values, and ... for relationships. For attributes which are themselves AbstractModels, it shows the class name to avoid extremely verbose inspections and infinite loops.



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/virtualbox/abstract_model.rb', line 215

def inspect
  values = []

  self.class.attributes.each do |name, options|
    value = read_attribute(name)
    value = if value.is_a?(AbstractModel)
      "#<#{value.class.name}>"
    else
      value.inspect
    end

    values.push("#{name.inspect}=#{value}")
  end

  self.class.relationships.each do |name, options|
    values.push("#{name.inspect}=...")
  end

  "#<#{self.class} #{values.sort.join(", ")}>".strip
end

- (Boolean) lazy_attribute?(*args)

Overriding Attributable#lazy_attribute? to always return false for new records, since new records shouldn't load lazy data.

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/virtualbox/abstract_model.rb', line 127

def lazy_attribute?(*args)
  return false if new_record?
  super
end

- (Boolean) lazy_relationship?(*args)

Overriding Relatable#lazy_relationship? to always return false for new records, since new records shouldn't load lazy data.

Returns:

  • (Boolean)


134
135
136
137
# File 'lib/virtualbox/abstract_model.rb', line 134

def lazy_relationship?(*args)
  return false if new_record?
  super
end

- (Object) new_record!

Explicitly resets the model to a new record. If you're using this method outside of virtualbox library core, you should really be asking yourself "why?"



54
55
56
# File 'lib/virtualbox/abstract_model.rb', line 54

def new_record!
  @new_record = true
end

- (Boolean) new_record?

Returns a boolean denoting if the record is new or existing. This method is provided for subclasses to use to differentiate between creating a new object or saving an existing one. An example of this is HardDrive#save which will create a new hard drive if it didn't previously exist, or save an old one if it did exist.

Returns:

  • (Boolean)


46
47
48
49
# File 'lib/virtualbox/abstract_model.rb', line 46

def new_record?
  new_record! if @new_record.nil?
  @new_record
end

- (Object) populate_attributes(attribs, opts = {})

Sets the initial attributes from a hash. This method is meant to be used once to initially setup the attributes. It is not a mass-assignment method for updating attributes.

This method does not affect dirtiness, but also does not clear it. This means that if you call populate_attributes, the same attributes that were dirty before the call will be dirty after the call (but no more and no less). This distinction is important because most subclasses of AbstractModel only save changed attributes, and ignore unchanged attributes. Attempting to change attributes through this method will cause them to not be saved, which is surely unexpected behaviour for most users.

Calling this method will also cause the model to assume that it is not a new record (see #new_record?).



154
155
156
157
158
159
160
161
162
163
# File 'lib/virtualbox/abstract_model.rb', line 154

def populate_attributes(attribs, opts={})
  ignore_dirty do
    super(attribs)

    populate_relationships(attribs) unless opts[:ignore_relationships]
  end

  # No longer a new record
  existing_record!
end

- (Object) populate_relationship(name, data)

Populates a single relationship with the given data.



178
179
180
181
# File 'lib/virtualbox/abstract_model.rb', line 178

def populate_relationship(name, data)
  existing_record!
  ignore_dirty { super }
end

- (Object) populate_relationships(data)

Loads and populates the relationships with the given data. This method is meant to be used once to initially setup the relatoinships.

This methods does not affect dirtiness, but also does not clear it.

Calling this method will also cuase the model to assume that it is not a new record (see #new_record?)



172
173
174
175
# File 'lib/virtualbox/abstract_model.rb', line 172

def populate_relationships(data)
  existing_record!
  ignore_dirty { super }
end

- (Object) reload!

Signals to the class that it should be reloaded. This simply toggles a boolean value to true. It is up to the subclass to implement functionality around it. See reload?



37
38
39
# File 'lib/virtualbox/abstract_model.rb', line 37

def reload!
  self.class.reload!
end

- (Object) save(*args)

Saves the model attributes and relationships.

The method can be passed any arbitrary arguments, which are implementation specific (see VM#save, which does this).



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/virtualbox/abstract_model.rb', line 98

def save(*args)
  # Go through changed attributes and call save_attribute for
  # those only
  changes.each do |key, values|
    save_attribute(key, values[1], *args)
  end

  # Go through and only save the loaded relationships, since
  # only those would be modified.
  self.class.relationships.each do |name, options|
    next if lazy_relationship?(name) && !loaded_relationship?(name)
    save_relationship(name, *args)
  end

  # No longer a new record
  @new_record = false
end

- (Object) save_attribute(key, value, *args)

Saves a single attribute of the model. This method on the abstract model does nothing on its own, and is expected to be overridden by any subclasses.

This method clears the dirty status of the attribute.



121
122
123
# File 'lib/virtualbox/abstract_model.rb', line 121

def save_attribute(key, value, *args)
  clear_dirty!(key)
end

- (Object) set_relationship(key, value)

Overwrites Relatable#set_relationship to set the dirty state of the relationship. See Dirty#set_dirty! as well.



192
193
194
195
196
# File 'lib/virtualbox/abstract_model.rb', line 192

def set_relationship(key, value)
  existing = relationship_data[key]
  new_value = super
  set_dirty!(key, existing, new_value)
end

- (Object) validate(*args)

Validates the model and relationships.



80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/virtualbox/abstract_model.rb', line 80

def validate(*args)
  # First clear all previous errors
  clear_errors

  # Then do the validations
  failed = false
  self.class.relationships.each do |name, options|
    next unless options && options[:klass].respond_to?(:validate_relationship)
    failed = true if !options[:klass].validate_relationship(self, relationship_data[name], *args)
  end

  return !failed
end

- (Object) write_attribute(name, value)

Overwrites Attributable#write_attribute to set the dirty state of the written attribute. See Dirty#set_dirty! as well.



185
186
187
188
# File 'lib/virtualbox/abstract_model.rb', line 185

def write_attribute(name, value)
  set_dirty!(name, read_attribute(name), value) unless lazy_attribute?(name) && !loaded_attribute?(name)
  super
end