Module: CouchObject::Persistable
- Defined in:
- lib/couch_object/persistable.rb,
lib/couch_object/persistable/meta_classes.rb,
lib/couch_object/persistable/overloaded_methods.rb,
lib/couch_object/persistable/has_many_relations_array.rb
Defined Under Namespace
Modules: ClassMethods Classes: HasManyRelation
Instance Attribute Summary collapse
-
#created_at ⇒ Object
readonly
Accessors for instance variables specific to the persistable CouchObject.
-
#id ⇒ Object
readonly
Accessors for instance variables specific to the persistable CouchObject.
-
#revision ⇒ Object
readonly
Accessors for instance variables specific to the persistable CouchObject.
-
#updated_at ⇒ Object
readonly
Accessors for instance variables specific to the persistable CouchObject.
Class Method Summary collapse
Instance Method Summary collapse
- #<(other_object) ⇒ Object
-
#<=(other_object) ⇒ Object
<= and >= Uses the results from the methods ==, < and > to determine the result.
-
#==(other_object) ⇒ Object
Equality is checked for using the following rules: * if the object types do not match the result is false * if the object_id of the class sent as an argument is the same as the object_id of self, equal returns true.
-
#>(other_object) ⇒ Object
Goal: The goal is to return true for the object which has the newest representation in the database.
- #>=(other_object) ⇒ Object
- #clone ⇒ Object
-
#couch_force_smart_save ⇒ Object
Forces the instance object into smart save mode.
-
#couch_object_origianl_clone ⇒ Object
When saved, clones and dupes are stored as separate documents from the object it originated from Returns: * A new instance of itself where the ID and revision number is set to nil * the new instance shares the same storage location as the object it originates from.
-
#couch_set_initial_state ⇒ Object
Stores the initial value of the instance to a variable for later reference by the
unsaved_changes?
method. -
#delete(db_uri = location) ⇒ Object
Any instance should be able to delete itself.
- #do_load_belongs_to_relations ⇒ Object (also: #do_load_belongs_to_relation)
- #do_load_has_many_relations ⇒ Object (also: #do_load_has_one_relations, #do_load_has_one_relation)
-
#do_not_load_belongs_to_relations ⇒ Object
If you need to access the belongs_to variable without loading the relation if it hasn’t already been loaded, you can call the instance method
do_not_load_belongs_to_relations
. -
#do_not_load_has_many_relations ⇒ Object
(also: #do_not_load_has_one_relations, #do_not_load_has_one_relation, #do_not_load_has_many_relation)
Sometimes you might want to add an object to a has_many relation without interacting with the other relations at all.
- #dup ⇒ Object
-
#end_relationsship_with(undersired_object, which_is_stored_as) ⇒ Object
Breaks relations if existing.
-
#new? ⇒ Boolean
Returns: *
true
if the object hasn’t been saved *false
if the object has previously been stored or is loaded from the document store. -
#save(db_uri = location) ⇒ Object
Saves the object to the db_uri supplied, or if not set, to the location the object has previously been saved to.
-
#set_location=(db_uri) ⇒ Object
(also: #set_storage_location=)
Sets the location variable manually.
-
#to_json ⇒ Object
serializes this object into JSON.
-
#unsaved_changes? ⇒ Boolean
Classes WITH smart_save activated: Any instance should be able to know if it has unsaved changes or not.
Instance Attribute Details
#created_at ⇒ Object (readonly)
Accessors for instance variables specific to the persistable CouchObject
296 297 298 |
# File 'lib/couch_object/persistable.rb', line 296 def created_at @created_at end |
#id ⇒ Object (readonly)
Accessors for instance variables specific to the persistable CouchObject
296 297 298 |
# File 'lib/couch_object/persistable.rb', line 296 def id @id end |
#revision ⇒ Object (readonly)
Accessors for instance variables specific to the persistable CouchObject
296 297 298 |
# File 'lib/couch_object/persistable.rb', line 296 def revision @revision end |
#updated_at ⇒ Object (readonly)
Accessors for instance variables specific to the persistable CouchObject
296 297 298 |
# File 'lib/couch_object/persistable.rb', line 296 def updated_at @updated_at end |
Class Method Details
.included(klazz) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
# File 'lib/couch_object/persistable/meta_classes.rb', line 3 def self.included(klazz) klazz.extend(ClassMethods) # # Using meta programming methods for handling, amongst others, # * setting of the database uri at design time # * including timestamps # * managing relations # are created # klazz.class_eval do ## # Timestamps ## # Timestamps are false by default def self.; false; end def self.; false; end # # Adds timestamps to the class. # # Example: # # class Vacation # include CouchObject::Persistable # add_timestamp_for :on_create, :on_update # end # # my_vacation = Vacation.new # my_vacation.save(db_address) # my_vacation.created_at => Somedate # my_vacation.updated_at => Somedate # def self.(*) .each do |action| case action when :on_create self.class_eval do def self.; true; end end when :on_update self.class_eval do def self.; true; end end end end end ## # Change monitor ## # to be implemented later. # could be implemented using MonitorFunctions # (http://www.erikveen.dds.nl/monitorfunctions/) # Each class monitors it's setters to see if it's content is changed, # in which case a flag is set. # For this purpose all setters are overridden # self.instance_variable_set("@couch_has_unsaved_changes_flag", false) # def unsaved_changes? # @couch_has_unsaved_changes_flag # end # puts "Public setters:" # self.public_methods.each do |method| # if method.to_s[-1,1] == "=" # # We have to create an alias for the original method # DO MAGIC HERE # end # end ## # Database storage location ## # Location methods are added both as instance methods and # as class level methods. The class level methods are needed # when loading new objects from the database and the instance # methods are used throughout the class def self.location; @couch_object_class_storage_location ||= nil; end def location; @location; end alias storage_location location # # Sets the location of the database to use by default # # Example: # # class AppleTree # include CouchObject::Persistable # database 'http://localhost:5984' # end # # apple_tree = AppleTree.new # apple_tree.save # saves automatically to the predefined # # database location # def self.database(db_uri) @couch_object_class_storage_location = db_uri self.instance_eval do define_method("location") do @location ||= db_uri end end end ## # Smart savign ## def use_smart_save; false; end # # Smart save (defaults to false), if activated, keeps a snapshot of # the objects initial state and evaluates if the class needs to be # saved to the database by comparing it to the snapshot when a save # is requested. # # Please notice: # Only activate this feature in cases where it is needed. # It might slow down the performance of your app if you activate it # for classes that you need many instances of and that you won't # call the save method on after having loaded them from the database. # Please also bare in mind that the class instance will store an # extra copy of its contents which will lead to quite a big memory # overhead for classes that store a lot of data! # def self.smart_save self.instance_eval do define_method("use_smart_save") do true end end end # # Smart save can also be used on a per-case basis if it is sometimes # needed and sometimes not. # # Example: # # user_without_smart_save_1 = User.get("foo") # User.smart_save # user_with_smart_save = User.get("bar") # User.deactivate_smart_save # user_without_smart_save_2 = User.get("bong") # def self.deactivate_smart_save self.instance_eval do define_method("use_smart_save") do false end end end ## # Relations ## # Default values for has_many, belongs_to and belongs_to_as def has_many; []; end def has_one; []; end def has; []; end def belongs_to; []; end # # Defines a has_many relation which then again # needs a corresponding belongs_to relation in the # classes the relation is made with (see the documentation # of belongs_to below) # # Takes: # * a symbol indicating the name of the association. # The association name can be freely chosen. # # Example: # # has_many :fruits # # Requires a belongs_to relation from the other part. F.ex: # # belongs_to: :fruit_basket, :as => :fruits # # Raises: # * HasManyAssociationError if the association name # is left blank. # def self.has_many(what_it_has = nil) raise CouchObject::Errors::HasManyAssociationError if what_it_has == nil @couch_object_has_many ||= [] @couch_object_has_many << what_it_has unless \ @couch_object_has_many.include?(what_it_has) self.instance_eval do # The objects are stored in this variable has_many_object_variable = \ "@couch_object_#{what_it_has.to_s}" # # Getter which also works as a setter because: # * it returns the array that contains the references # * when a new relationship is added using << the action # it performed by the array, and not self # define_method(what_it_has.to_s) do eval("#{has_many_object_variable}.nil? ? " + \ "#{has_many_object_variable} = " + \ "couch_load_has_many_relations(\"#{what_it_has}\") : " + \ "#{has_many_object_variable}") end # # Returns: # * the name of the relation # # Example: # # apple_tree.has_many => :fruits # apple_tree.fruits => [apple1, apple2] # all_the_things_it_has = @couch_object_has_many define_method("has_many") do # Filtering out the has_one relations so they don't show up what_is_has_output = [] self.send(:has).each do |has| what_is_has_output << has \ unless has.to_s[0..7] == "has_one_" end what_is_has_output end define_method("has") do all_the_things_it_has end end end # # Defines a belongs_to relation which then again # needs a corresponding has_many relation in the # class the relation is made with (see the documentation # of has_many above) # # Takes: # * a symbol indicating the name of the association. # The association name can be freely chosen. # * a symbol that indicates the name the corresponding has_many # relationship in the owner class # # Example: # # belongs_to :fruit_basket, :as => :fruits # # Requires a has_many relation from the other class that looks # something like this: # # has_many :fruits # # Raises: # * BelongsToAssociationError if the association name, # or the :as parameter is left blank. # def self.belongs_to(what_it_belongs_to = nil, as = nil) raise CouchObject::Errors::BelongsToAssociationError \ if what_it_belongs_to.nil? || as.nil? @couch_object_what_it_belongs_to ||= [] @couch_object_what_it_belongs_to << what_it_belongs_to unless \ @couch_object_what_it_belongs_to.include?(what_it_belongs_to) self.instance_eval do # The object are stored in this variable belongs_to_object_variable = \ "@couch_object_#{what_it_belongs_to.to_s}" # Getter define_method(what_it_belongs_to.to_s) do eval("#{belongs_to_object_variable} ||= " + \ " couch_load_belongs_to_relation(\"#{as[:as]}\")") end # Setter define_method("#{what_it_belongs_to.to_s}=") do |object_to_add| # The first thing we have to do is to check if it is in # a has_one or has_many relationship! if object_to_add.respond_to?("has_one_#{as[:as]}") || \ eval("#{belongs_to_object_variable}" + \ ".respond_to?(:has_one_#{as[:as]})") is_a_has_many_relationship = false else is_a_has_many_relationship = true end # Now... there is no good reason loading a belongs_to relation # from the database only to remove the relation with the child, # because the relation is stored in the child anyway... # We therefore temporarily deactivate the loading of belongs_to # relations original_state_of_load_belongs_to_relations = \ @do_not_load_belongs_to_relations @do_not_load_belongs_to_relations = true if is_a_has_many_relationship # Remove the original relationship in the master object eval("#{belongs_to_object_variable}." \ + "send(:end_relationsship_with, self, \"#{as[:as]}\" ) " \ + "unless #{belongs_to_object_variable} == nil") # Sets the new relation instance_variable_set("#{belongs_to_object_variable}", \ object_to_add) # Set up the new relationship with the master object self.add_relation_to_master(as[:as]) if object_to_add else # Remove old relationship and set the new one self.set_has_one_relation_to_master(as[:as], nil) # Sets the new relation instance_variable_set("#{belongs_to_object_variable}", \ object_to_add) # Setup the new relationship self.set_has_one_relation_to_master(as[:as], self) \ if object_to_add end # And now we reset the @do_not_load_belongs_to_relations # variable to its original value: @do_not_load_belongs_to_relations = \ original_state_of_load_belongs_to_relations end # Setter without callback for new objects # from the load relations method define_method("#{what_it_belongs_to.to_s}" + \ "_without_call_back=") do |object_to_add| # Sets the new relation instance_variable_set("#{belongs_to_object_variable}", \ object_to_add) end # # Returns: # * the getter for a belongs_to relationship as a symbol # # Example: # # fruit.belongs_to => :tree # fruit.tree => <AppleTree> # return_value_for_function = @couch_object_what_it_belongs_to define_method("belongs_to") do return_value_for_function end # # Returns: # * what the corresponding has_many relation is called # # Example: # # fruit.belongs_to => :tree # fruit.tree = apple_tree # fruit.belongs_to_as => :fruits # apple_tree.fruits => [fruit] # define_method("belongs_to_#{what_it_belongs_to}_as") do as[:as] end end end # # has_one relations are added as a layer to the has_many # There is created a has_many relation ship but getters and setters # for the has_one relationship on top of that that interact with the # has_many relationship. def self.has_one(what_it_has = nil) raise CouchObject::Errors::HasOneAssociationError if what_it_has == nil = "has_one_#{what_it_has.to_s}".to_sym # Create the has_many relationship self.send(:has_many, ) # Create methods to get and set the relationship # getter define_method(what_it_has) do self.send().first end define_method("#{what_it_has}=") do |new_relation| # Remove the original relation self.send(). remove(self.send().first) \ unless self.send() == [] # Disable callbacks self.send().disable_call_back_on_add if new_relation # Create the new self.send() << new_relation \ unless new_relation == nil # Set the relationship in the child what_it_belongs_to = define_relationship_name(new_relation) new_relation. send("#{what_it_belongs_to}_without_call_back=", self) end # Reenable callbacks self.send().enable_call_back_on_add end define_method("has_one") do what_is_has_output = [] self.send(:has).each do |has| what_is_has_output << has.to_s[8..-1].to_sym \ if has.to_s[0..7] == "has_one_" end what_is_has_output end end # # Returns the name of the relation in itself matching one of the # relations in the other object # # Example: # other_object has defined the relationships: # belongs_to :house, :as => :houses # belongs_to :humanity # # self has the relation # has_many :houses # # :houses is returned # def define_relationship_name(other_object) belongs_to_relationship_name = nil other_object.send(:belongs_to).each do |what_it_belongs_to| name_of_relation_in_master = other_object. send("belongs_to_#{what_it_belongs_to}_as".to_sym) return what_it_belongs_to.to_s \ if self.respond_to?(name_of_relation_in_master) end # There couldn't be found a match... raising an error raise "The master class #{self} doesn't have a relation" + \ " matching the relation defined in the child class " \ if belongs_to_relationship_name == nil end # # This method is called from the method that assigns a # belongs_to relation to inform the master object of the relation # (has_many relations) # def add_relation_to_master(relation_name) if master_class = get_master_for_relation(relation_name) masters_objects_relations = \ master_class.send(relation_name) if masters_objects_relations == [] masters_objects_relations << self else unless masters_objects_relations.include?(self) masters_objects_relations << self end end end end # # This method is called from the method that assigns a # belongs_to relation to inform the master object of the relation # (has_one relations) # def set_has_one_relation_to_master(relation_name, to_what) if master_class = get_master_for_relation(relation_name) # set up the new relationship in the master master_class.send("#{relation_name}=", to_what) end end # # This method is called from the method that assigns a # belongs_to relation to inform the previous master object # that the relation ship has ended # (has_one relations) # def end_has_one_relation_to_master(relation_name) set_has_one_relation_to_master(relation_name, nil) end def get_master_for_relation(relation_name) accessor_for_what_it_belongs_to = nil self.send(:belongs_to).each do |what_it_belongs_to| # Only load the belongs to relation that is needed # We therefore have to find out which of the relations to use find_string = "belongs_to_#{what_it_belongs_to}_as" accessor_for_what_it_belongs_to = what_it_belongs_to \ if self.send(find_string) == relation_name end return nil if accessor_for_what_it_belongs_to == nil master_class = self.send(accessor_for_what_it_belongs_to) return nil if master_class == nil raise "The master class doesn't have a matching relation " + \ "defined" unless master_class.respond_to?(relation_name) return master_class end end end |
.use_smart_save ⇒ Object
332 333 334 |
# File 'lib/couch_object/persistable.rb', line 332 def self.use_smart_save true end |
Instance Method Details
#<(other_object) ⇒ Object
127 128 129 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 127 def <(other_object) other_object > self end |
#<=(other_object) ⇒ Object
<= and >= Uses the results from the methods ==, < and > to determine the result
Takes:
-
other_object
to compare size with
Raises:
-
CantCompareSize when trying to compare two object that have not been saved or saved but do not have timestamps and that are not equal
Returns:
-
true or false
145 146 147 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 145 def <=(other_object) self == other_object || self < other_object ? true : false end |
#==(other_object) ⇒ Object
Equality is checked for using the following rules:
-
if the object types do not match the result is false
-
if the object_id of the class sent as an argument is the same as the object_id of self, equal returns true.
-
if the two objects have a different class type it fails as a result of the object_id test above which can’t be true
-
fails if the object_id or revision numbers are different
-
it fails if one or both of the objects are new and they don’t share the object_id, because in that case they will be stored as separate documents in the database
-
is true if all instance_variables are the same
Takes:
-
other_object
which is any object one wishes to compare self to
Returns:
-
true or false
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 51 def ==(other_object) return false unless self.class == other_object.class return true if self.object_id == other_object.object_id return false if self.id != other_object.id || \ self.revision != other_object.revision return false if self.new? || other_object.new? # All relations should be loaded so that the comparison can be realistic has.each do |what_is_has| self.send(what_is_has) other_object.send(what_is_has) if other_object. respond_to?(what_is_has) end belongs_to.each do |what_it_belongs_to| self.send(what_it_belongs_to) other_object.send(what_it_belongs_to) if other_object. respond_to?(what_it_belongs_to) end self.instance_variables.each do |var| return false if eval(var).to_s != \ other_object.instance_variable_get(var).to_s end # has to be true because else it would already have failed :) true end |
#>(other_object) ⇒ Object
Goal: The goal is to return true for the object which has the newest representation in the database.
Requires:
-
that both objects have timestamps
Returns:
-
false if they are equal objects.
-
true if self has been saved while the other_object has not.
-
false if self hasn’t been saved but the other_object has
-
true if both have been saved and self has been saved more recently.
-
false if both have been saved but the other object more recently.
Takes:
-
other_object
to compare size with
Raises:
-
CantCompareSize when trying to compare two object that have not been saved or saved but do not have timestamps
Returns:
-
true or false
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 104 def >(other_object) return false if self == other_object unless self.new? && other_object.new? if self.class. and \ other_object.class. return ((self.updated_at || 0).to_i \ > (other_object.updated_at || 0).to_i) \ ? true : false elsif self.class. and \ other_object.class. return ((self.created_at || 0).to_i \ > (other_object.created_at || 0).to_i) \ ? true : false else # Both or one of them does not have a timestamp, # so we can't really compare them raise CouchObject::Errors::CantCompareSize end else raise CouchObject::Errors::CantCompareSize end end |
#>=(other_object) ⇒ Object
148 149 150 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 148 def >=(other_object) other_object <= self end |
#clone ⇒ Object
20 21 22 23 24 25 26 27 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 20 def clone new_clone = self.couch_object_origianl_clone new_clone.instance_variable_set("@id", nil) new_clone.instance_variable_set("@revision", nil) # return the new clone new_clone end |
#couch_force_smart_save ⇒ Object
Forces the instance object into smart save mode
331 332 333 334 335 |
# File 'lib/couch_object/persistable.rb', line 331 def couch_force_smart_save def self.use_smart_save true end end |
#couch_object_origianl_clone ⇒ Object
When saved, clones and dupes are stored as separate documents from the object it originated from
Returns:
-
A new instance of itself where the ID and revision number is set to nil
-
the new instance shares the same storage location as the object it originates from.
19 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 19 alias couch_object_origianl_clone clone |
#couch_set_initial_state ⇒ Object
Stores the initial value of the instance to a variable for later reference by the unsaved_changes?
method
315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/couch_object/persistable.rb', line 315 def couch_set_initial_state # For the unsaved_changes? instance method to work, we have to # supply a snapshot of what the fresh object looked like. # BUT ONLY if the user has activated the smart_save option if use_smart_save @couch_initial_load = true @couch_object_original_state = to_json @couch_initial_load = false end end |
#delete(db_uri = location) ⇒ Object
Any instance should be able to delete itself
Takes:
-
db_uri
if not set in the location variable
Returns:
-
true on success
-
false on failure
Note:
-
it also deletes all has_many relations from the database
-
it removes itself from object it belongs to
Raises:
-
CouchObject::Errors::NoDatabaseLocationSet if
db_uri
is blank AND has not been set on class level
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 |
# File 'lib/couch_object/persistable.rb', line 585 def delete(db_uri = location) perform_callback(:before_delete) unless new? # Raises an error if the location variable hasn't been set raise CouchObject::Errors::NoDatabaseLocationSet unless db_uri db = CouchObject::Database.open(db_uri) # Removes itself from the database db.delete(id, revision) end # Remove all relations has_many.each do |what_it_has| self.send(what_it_has).dup.each do || .delete end end # Remove the relationship with it's has many master object belongs_to.each do |what_it_belongs_to| self_belongs_to_classtype = what_it_belongs_to self_belongs_to_classtype_as = self. send("belongs_to_#{what_it_belongs_to}_as") self_belongs_to_class = self.send(self_belongs_to_classtype) unless \ self_belongs_to_classtype.nil? self_belongs_to_class.end_relationsship_with(self, self_belongs_to_classtype_as) unless self_belongs_to_class.nil? # Remove the relationship with it's belongs_to master from itself remove_call = "#{self_belongs_to_classtype.to_s}" + \ "_without_call_back=" self.send(remove_call.to_sym, nil) if self_belongs_to_classtype end # Reset itself @id = nil @revision = nil @location = nil perform_callback(:after_delete) true end |
#do_load_belongs_to_relations ⇒ Object Also known as: do_load_belongs_to_relation
838 839 840 |
# File 'lib/couch_object/persistable.rb', line 838 def do_load_belongs_to_relations @do_not_load_belongs_to_relations = false end |
#do_load_has_many_relations ⇒ Object Also known as: do_load_has_one_relations, do_load_has_one_relation
820 821 822 |
# File 'lib/couch_object/persistable.rb', line 820 def do_load_has_many_relations @do_not_load_has_many_relations = false end |
#do_not_load_belongs_to_relations ⇒ Object
If you need to access the belongs_to variable without loading the relation if it hasn’t already been loaded, you can call the instance method do_not_load_belongs_to_relations
. To reactivate loading so the relation is loaded the next time it is needed, call the instance method do_load_belongs_to_relations
.
835 836 837 |
# File 'lib/couch_object/persistable.rb', line 835 def do_not_load_belongs_to_relations @do_not_load_belongs_to_relations = true end |
#do_not_load_has_many_relations ⇒ Object Also known as: do_not_load_has_one_relations, do_not_load_has_one_relation, do_not_load_has_many_relation
Sometimes you might want to add an object to a has_many relation without interacting with the other relations at all. In cases like that, when loading all the relations would just cause unnecessary traffic to the database, you can tell the object not to load it has_many relations using this method
817 818 819 |
# File 'lib/couch_object/persistable.rb', line 817 def do_not_load_has_many_relations @do_not_load_has_many_relations = true end |
#dup ⇒ Object
28 29 30 |
# File 'lib/couch_object/persistable/overloaded_methods.rb', line 28 def dup clone end |
#end_relationsship_with(undersired_object, which_is_stored_as) ⇒ Object
Breaks relations if existing
Takes:
-
undesired_object
as a reference to the object the relationship should be broken with -
which_is_stored_as
(string) which is what the relation is stored as.
646 647 648 |
# File 'lib/couch_object/persistable.rb', line 646 def end_relationsship_with(undersired_object, which_is_stored_as) self.send(which_is_stored_as.to_sym).perform_remove(undersired_object) end |
#new? ⇒ Boolean
Returns:
-
true
if the object hasn’t been saved -
false
if the object has previously been stored or is loaded from the document store
307 308 309 |
# File 'lib/couch_object/persistable.rb', line 307 def new? id.nil? || revision.nil? end |
#save(db_uri = location) ⇒ Object
Saves the object to the db_uri supplied, or if not set, to the location the object has previously been saved to.
Takes:
-
db_uri
as string which is the location of the database: Example: localhost:5984/mydb
Raises:
-
CouchObject::Errors::NoDatabaseLocationSet error if the object doesn’t have a previously set location and the
db_uri
is nil
Returns:
-
Hash with the id and revision: => “1234”, :revision => “ABC123”
Sub methods might raise:
-
CouchObject::Errors::DatabaseSaveFailed if the save fails
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/couch_object/persistable.rb', line 357 def save(db_uri = location) # if the location hasn't been set, set it @location ||= db_uri # Raises an error if the location variable hasn't been set raise CouchObject::Errors::NoDatabaseLocationSet unless location # If it's belongs_to relationships haven't been saved # then it has be done first. # Saving the master will also automatically save the child performed_save = false # If the belongs_to relationships haven't already been loaded, # there is reason to believe that: # * The object is new and doesn't have any relation set # * The object already knows about it's belongs_to relations # and doesn't need aditional information about them for saving # We therefore deactivate the loading of belongs_to relations original_state_of_load_belongs_to_relations = \ @do_not_load_belongs_to_relations @do_not_load_belongs_to_relations = true belongs_to.each do |what_it_belongs_to| master_class = self.send(what_it_belongs_to) unless master_class == nil || !master_class.new? master_class.save performed_save = true end end # Reset the do_not_load_belongs_to_relations variable to its # original state @do_not_load_belongs_to_relations = \ original_state_of_load_belongs_to_relations # If none of the master classes were saved, meaning they weren't new # or didn't exist, then we have to manually save this object. couch_perform_save unless performed_save {:id => @id, :revision => @revision} end |
#set_location=(db_uri) ⇒ Object Also known as: set_storage_location=
Sets the location variable manually
Takes:
-
db_uri
as string which is the location of the database: Example: localhost:5984/mydb
657 658 659 |
# File 'lib/couch_object/persistable.rb', line 657 def set_location=(db_uri) @location = db_uri == "" ? nil : db_uri end |
#to_json ⇒ Object
serializes this object into JSON
Returns:
-
The values of the class in json format
Example “class”:“Bike”,“attributes”:{“wheels”:2}
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 |
# File 'lib/couch_object/persistable.rb', line 671 def to_json parameters = {} parameters["class"] = self.class if respond_to?(:to_couch) parameters["attributes"] = self.to_couch else # Find all the instance variables and add them to the # attributes parameter p_attributes = {} instance_variables = \ self.instance_variables - ["@location", "@created_at", "@updated_at", "@id", "@revision", "@do_not_load_has_many_relations", "@do_not_load_belongs_to_relations", "@couch_object_original_state", "@couch_initial_load", "@belongs_to"] # We also have to remove all the objects that are related # through belongs_to and has_many relations. They have to be called # saved separately has.each do |thing_it_has| instance_variables = instance_variables - \ ["@couch_object_#{thing_it_has.to_s}"] end belongs_to.each do |things_it_belongs_to| instance_variables = instance_variables - \ ["@couch_object_#{things_it_belongs_to.to_s}"] end instance_variables.each do |var| p_attributes[var[1..(var.length)]] = self.instance_variable_get(var) end parameters["attributes"] = p_attributes end parameters["updated_at"] = Time.now \ if self.class:: unless new? parameters["_id"] = id parameters["_rev"] = revision parameters["created_at"] = created_at \ if self.class:: else parameters["created_at"] = Time.now \ if self.class:: end # If it is in belongs_to relationship(s), then that fact # has to be stored in the database if belongs_to != [] and !@couch_initial_load # the couch_initial_load # is to get the initial # state of the object # without loading the # belongs_to relations # which would start an # infinite loop. # NOTE: this is only for # cases where smart_save # has been activated. # No reason to load the belongs_to relations if they haven't # already been loaded from the database! original_state_of_load_belongs_to_relations = \ @do_not_load_belongs_to_relations @do_not_load_belongs_to_relations = true what_it_belongs_to = {} self.send(:belongs_to).each do |relation| as_what = self.send("belongs_to_#{relation}_as") object_it_belongs_to = self.send(relation) # Unless the relation is unset, in which case it will be of # type NilClass, set it. what_it_belongs_to[as_what.to_s] = object_it_belongs_to.id || "new" \ unless object_it_belongs_to.class == NilClass end # Reset the value so they are loaded the next time when needed # if that is what the user wants. @do_not_load_belongs_to_relations = \ original_state_of_load_belongs_to_relations # We have to make sure the @belongs_to variable contains all changes # and all the original values for the keys that haven't changed/ # relations that haven't been loaded original_belongs_to = @belongs_to || {} @belongs_to = what_it_belongs_to times_through = 1 # LOOP 1... see below for problem description original_belongs_to.each_pair do |key, value| times_through += 1 @belongs_to[key.to_s] = value unless @belongs_to[key.to_s] end # FIXME: # Now... this is a really hacky way to solve this problem # and should be improved... Feel free to come up with sollutions # Case: # If it has a belongs_to relationship that is new and therefore # doesn't have an ID it would normally be written in the @belongs_to # variable as nil. The problem is that if self has previously # been saved with another parent object this ID would still come # through in the @belongs_to variable updater (see "LOOP 1" above). # We therefore assign the ID "new" to all unsaved relations, which we # now have to nilify. If we don't the smart save wont work for this # type of cases. end parameters["belongs_to"] = @belongs_to parameters.delete("belongs_to") if @belongs_to == {} or @belongs_to == nil # if @couch_initial_load && @belongs_to begin parameters.to_json rescue JSON::GeneratorError # All strings aren't encoded properly, so we have to force them into # UTF-8. # FIXME: The kconv library has some weird artefacts though where # a lot of Norwegian (Scandianavian?) letters get turned into # asian characters of some sort! CouchObject::Utils::decode_strings(parameters).to_json end end |
#unsaved_changes? ⇒ Boolean
Classes WITH smart_save activated: Any instance should be able to know if it has unsaved changes or not. When an instance is loaded from the DB it creates a snapshot of what its variables contain. Based on a comparison between the snapshot and the contents of the instance this method returns true or false.
Classes WITHOUT smart_save activated: Will always return true regardless of what state it is in
A new object will always return true
Returns:
-
true: if it has changes that haven’t been saved to the database
-
fase: if the nothing has changed since it was loaded from the database.
559 560 561 562 563 564 565 |
# File 'lib/couch_object/persistable.rb', line 559 def unsaved_changes? return true if new? return true unless use_smart_save @couch_object_original_state == self.to_json ? false : true end |