Class: CouchRest::ExtendedDocument

Inherits:
Document show all
Includes:
Callbacks, Mixins::AttributeProtection, Mixins::ClassProxy, Mixins::Collection, Mixins::DesignDoc, Mixins::DocumentQueries, Mixins::ExtendedAttachments, Mixins::Views
Defined in:
lib/couchrest/more/extended_document.rb

Overview

Same as CouchRest::Document but with properties and validations

Instance Attribute Summary (collapse)

Attributes inherited from Document

#database

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from Mixins::AttributeProtection

#accessible_properties, included, #protected_properties, #remove_protected_attributes

Methods included from Mixins::Collection

included

Methods included from Mixins::ClassProxy

included

Methods included from Mixins::ExtendedAttachments

#attachment_uri, #attachment_url, #create_attachment, #delete_attachment, #has_attachment?, #read_attachment, #update_attachment

Methods included from Mixins::DesignDoc

included

Methods included from Mixins::Views

included

Methods included from Mixins::DocumentQueries

included

Methods included from Callbacks

included, #run_callbacks

Methods inherited from Document

#copy, #id, #new?, #rev, #uri, use_database

Methods included from Mixins::Attachments

#delete_attachment, #fetch_attachment, #put_attachment

Methods inherited from Response

#[], #[]=

Methods inherited from Hash

===

Constructor Details

- (ExtendedDocument) initialize(passed_keys = {}, options = {})



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/couchrest/more/extended_document.rb', line 52

def initialize(passed_keys={}, options={})
  apply_defaults # defined in CouchRest::Mixins::Properties
  remove_protected_attributes(passed_keys) unless options[:directly_set_attributes]
  directly_set_attributes(passed_keys) unless passed_keys.nil?
  super(passed_keys)
  cast_keys      # defined in CouchRest::Mixins::Properties
  unless self['_id'] && self['_rev']
    self['couchrest-type'] = self.class.to_s
  end
  after_initialize if respond_to?(:after_initialize)
end

Instance Attribute Details

- (Object) casted_by

Accessors



36
37
38
# File 'lib/couchrest/more/extended_document.rb', line 36

def casted_by
  @casted_by
end

Class Method Details

+ (Object) create(options)

Defines an instance and save it directly to the database

Returns

returns the reloaded document


68
69
70
71
72
# File 'lib/couchrest/more/extended_document.rb', line 68

def self.create(options)
  instance = new(options)
  instance.create
  instance
end

+ (Object) create!(options)

Defines an instance and save it directly to the database

Returns

returns the reloaded document or raises an exception


78
79
80
81
82
# File 'lib/couchrest/more/extended_document.rb', line 78

def self.create!(options)
  instance = new(options)
  instance.create!
  instance
end

+ (Object) create_from_database(passed_keys = {})

Creates a new instance, bypassing attribute protection

Returns

a document instance


48
49
50
# File 'lib/couchrest/more/extended_document.rb', line 48

def self.create_from_database(passed_keys={})
  new(passed_keys, :directly_set_attributes => true)      
end

+ (Object) inherited(subklass)



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/couchrest/more/extended_document.rb', line 23

def self.inherited(subklass)
  super
  subklass.send(:include, CouchRest::Mixins::Properties)
  subklass.class_eval <<-EOS, __FILE__, __LINE__ + 1
    def self.inherited(subklass)
      super
      subklass.properties = self.properties.dup
    end
  EOS
  subclasses << subklass
end

+ (Object) method_missing(m, *args, &block)

Temp solution to make the view_by methods available



121
122
123
124
125
126
127
128
# File 'lib/couchrest/more/extended_document.rb', line 121

def self.method_missing(m, *args, &block)
  if has_view?(m)
    query = args.shift || {}
    view(m, query, *args, &block)
  else
    super
  end
end

+ (Object) subclasses



19
20
21
# File 'lib/couchrest/more/extended_document.rb', line 19

def self.subclasses
  @subclasses ||= []
end

+ (Object) timestamps!

Automatically set updated_at and created_at fields on the document whenever saving occurs. CouchRest uses a pretty decent time format by default. See Time#to_json



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/couchrest/more/extended_document.rb', line 87

def self.timestamps!
  class_eval <<-EOS, __FILE__, __LINE__
    property(:updated_at, :read_only => true, :type => 'Time', :auto_validation => false)
    property(:created_at, :read_only => true, :type => 'Time', :auto_validation => false)
    
    set_callback :save, :before do |object|
      object['updated_at'] = Time.now
      object['created_at'] = object['updated_at'] if object.new?
    end
  EOS
end

+ (Object) unique_id(method = nil, &block)

Name a method that will be called before the document is first saved, which returns a string to be used for the document's _id. Because CouchDB enforces a constraint that each id must be unique, this can be used to enforce eg: uniq usernames. Note that this id must be globally unique across all document types which share a database, so if you'd like to scope uniqueness to this class, you should use the class name as part of the unique id.



106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/couchrest/more/extended_document.rb', line 106

def self.unique_id method = nil, &block
  if method
    define_method :set_unique_id do
      self['_id'] ||= self.send(method)
    end
  elsif block
    define_method :set_unique_id do
      uniqid = block.call(self)
      raise ArgumentError, "unique_id block must not return nil" if uniqid.nil?
      self['_id'] ||= uniqid
    end
  end
end

Instance Method Details

- (Object) base_doc

Gets a reference to the actual document in the DB Calls up to the next document if there is one, Otherwise we're at the top and we return self



143
144
145
146
# File 'lib/couchrest/more/extended_document.rb', line 143

def base_doc
  return self if base_doc?
  @casted_by.base_doc
end

- (Boolean) base_doc?

Checks if we're the top document



149
150
151
# File 'lib/couchrest/more/extended_document.rb', line 149

def base_doc?
  !@casted_by
end

- (Object) create(bulk = false)

Trigger the callbacks (before, after, around) and create the document It's important to have a create callback since you can't check if a document was new after you saved it

When creating a document, both the create and the save callbacks will be triggered.



185
186
187
188
189
190
191
192
193
# File 'lib/couchrest/more/extended_document.rb', line 185

def create(bulk = false)
  caught = catch(:halt)  do
    _run_create_callbacks do
        _run_save_callbacks do
          create_without_callbacks(bulk)
      end
    end
  end
end

- (Object) create!

Creates the document in the db. Raises an exception if the document is not created properly.



205
206
207
# File 'lib/couchrest/more/extended_document.rb', line 205

def create!
  raise "#{self.inspect} failed to save" unless self.create
end

- (Object) create_without_callbacks(bulk = false)

unlike save, create returns the newly created document

Raises:

  • (ArgumentError)


196
197
198
199
200
201
# File 'lib/couchrest/more/extended_document.rb', line 196

def create_without_callbacks(bulk =false)
  raise ArgumentError, "a document requires a database to be created to (The document or the #{self.class} default database were not set)" unless database
  set_unique_id if new? && self.respond_to?(:set_unique_id)
  result = database.save_doc(self, bulk)
  (result["ok"] == true) ? self : false
end

- (Object) destroy(bulk = false)

Deletes the document from the database. Runs the :destroy callbacks. Removes the _id and _rev fields, preparing the document to be saved to a new _id.



259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/couchrest/more/extended_document.rb', line 259

def destroy(bulk=false)
  caught = catch(:halt)  do
    _run_destroy_callbacks do
      result = database.delete_doc(self, bulk)
      if result['ok']
        self.delete('_rev')
        self.delete('_id')
      end
      result['ok']
    end
  end
end

- (Object) properties

Returns the Class properties

Returns

Array

the list of properties for the instance



136
137
138
# File 'lib/couchrest/more/extended_document.rb', line 136

def properties
  self.class.properties
end

- (Object) save(bulk = false)

Trigger the callbacks (before, after, around) and save the document



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/couchrest/more/extended_document.rb', line 227

def save(bulk = false)
  caught = catch(:halt)  do
    if self.new?
      _run_save_callbacks do
        save_without_callbacks(bulk)
      end
    else
      update(bulk)
    end
  end
end

- (Object) save!

Saves the document to the db using save. Raises an exception if the document is not saved properly.



251
252
253
254
# File 'lib/couchrest/more/extended_document.rb', line 251

def save!
  raise "#{self.inspect} failed to save" unless self.save
  true
end

- (Object) save_without_callbacks(bulk = false)

Overridden to set the unique ID. Returns a boolean value

Raises:

  • (ArgumentError)


241
242
243
244
245
246
247
# File 'lib/couchrest/more/extended_document.rb', line 241

def save_without_callbacks(bulk = false)
  raise ArgumentError, "a document requires a database to be saved to (The document or the #{self.class} default database were not set)" unless database
  set_unique_id if new? && self.respond_to?(:set_unique_id)
  result = database.save_doc(self, bulk)
  mark_as_saved 
  result["ok"] == true
end

- (Object) update(bulk = false)

Trigger the callbacks (before, after, around) only if the document isn't new



211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/couchrest/more/extended_document.rb', line 211

def update(bulk = false)
  caught = catch(:halt)  do
    if self.new?
      save(bulk)
    else
      _run_update_callbacks do
        _run_save_callbacks do
          save_without_callbacks(bulk)
        end
      end
    end
  end
end

- (Object) update_attributes(hash)

Takes a hash as argument, and applies the values by using writer methods for each key. Raises a NoMethodError if the corresponding methods are missing. In case of error, no attributes are changed.



170
171
172
173
# File 'lib/couchrest/more/extended_document.rb', line 170

def update_attributes(hash)
  update_attributes_without_saving hash
  save
end

- (Object) update_attributes_without_saving(hash) Also known as: attributes=

Takes a hash as argument, and applies the values by using writer methods for each key. It doesn't save the document at the end. Raises a NoMethodError if the corresponding methods are missing. In case of error, no attributes are changed.



156
157
158
159
160
161
162
163
164
# File 'lib/couchrest/more/extended_document.rb', line 156

def update_attributes_without_saving(hash)
  # remove attributes that cannot be updated, silently ignoring them
  # which matches Rails behavior when, for instance, setting created_at.
  # make a copy, we don't want to change arguments
  attrs = hash.dup
  %w[_id _rev created_at updated_at].each {|attr| attrs.delete(attr)}
  check_properties_exist(attrs)
			set_attributes(attrs)
end