norr-couchrest 0.33.02 → 0.33.06
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -9
- data/lib/couchrest.rb +2 -2
- data/lib/couchrest/core/database.rb +0 -18
- data/lib/couchrest/core/design.rb +6 -4
- data/lib/couchrest/core/document.rb +3 -2
- data/lib/couchrest/mixins/callbacks.rb +187 -138
- data/lib/couchrest/mixins/collection.rb +3 -16
- data/lib/couchrest/mixins/design_doc.rb +6 -3
- data/lib/couchrest/mixins/properties.rb +74 -45
- data/lib/couchrest/mixins/validation.rb +18 -29
- data/lib/couchrest/more/casted_model.rb +29 -1
- data/lib/couchrest/more/extended_document.rb +55 -17
- data/lib/couchrest/more/property.rb +19 -0
- data/lib/couchrest/support/class.rb +81 -67
- data/lib/couchrest/support/rails.rb +12 -5
- data/spec/couchrest/core/database_spec.rb +2 -2
- data/spec/couchrest/more/casted_extended_doc_spec.rb +2 -4
- data/spec/couchrest/more/casted_model_spec.rb +229 -0
- data/spec/couchrest/more/extended_doc_spec.rb +148 -15
- data/spec/couchrest/more/extended_doc_view_spec.rb +17 -6
- data/spec/couchrest/more/property_spec.rb +66 -1
- data/spec/fixtures/more/article.rb +2 -2
- data/spec/fixtures/more/cat.rb +1 -0
- data/spec/fixtures/more/person.rb +1 -0
- metadata +2 -3
@@ -1,14 +1,5 @@
|
|
1
1
|
module CouchRest
|
2
2
|
module Mixins
|
3
|
-
module PaginatedResults
|
4
|
-
def amount_pages
|
5
|
-
@amount_pages ||= 0
|
6
|
-
end
|
7
|
-
def amount_pages=(value)
|
8
|
-
@amount_pages = value
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
3
|
module Collection
|
13
4
|
|
14
5
|
def self.included(base)
|
@@ -93,8 +84,6 @@ module CouchRest
|
|
93
84
|
DEFAULT_PAGE = 1
|
94
85
|
DEFAULT_PER_PAGE = 30
|
95
86
|
|
96
|
-
attr_accessor :amount_pages
|
97
|
-
|
98
87
|
# Create a new CollectionProxy to represent the specified view. If a
|
99
88
|
# container class is specified, the proxy will create an object of the
|
100
89
|
# given type for each row that comes back from the view. If no
|
@@ -122,11 +111,8 @@ module CouchRest
|
|
122
111
|
def paginate(options = {})
|
123
112
|
page, per_page = parse_options(options)
|
124
113
|
results = @database.view(@view_name, pagination_options(page, per_page))
|
125
|
-
@amount_pages ||= (results['total_rows'].to_f / per_page.to_f).ceil
|
126
114
|
remember_where_we_left_off(results, page)
|
127
115
|
results = convert_to_container_array(results)
|
128
|
-
results.extend(PaginatedResults)
|
129
|
-
results.amount_pages = @amount_pages
|
130
116
|
results
|
131
117
|
end
|
132
118
|
|
@@ -204,8 +190,9 @@ module CouchRest
|
|
204
190
|
def pagination_options(page, per_page)
|
205
191
|
view_options = @view_options.clone
|
206
192
|
if @last_key && @last_docid && @last_page == page - 1
|
207
|
-
view_options.delete(:key)
|
208
|
-
|
193
|
+
key = view_options.delete(:key)
|
194
|
+
end_key = view_options[:endkey] || key
|
195
|
+
options = { :startkey => @last_key, :endkey => end_key, :startkey_docid => @last_docid, :limit => per_page, :skip => 1 }
|
209
196
|
else
|
210
197
|
options = { :limit => per_page, :skip => per_page * (page - 1) }
|
211
198
|
end
|
@@ -30,11 +30,14 @@ module CouchRest
|
|
30
30
|
|
31
31
|
def default_design_doc
|
32
32
|
{
|
33
|
-
"language" => "
|
33
|
+
"language" => "javascript",
|
34
34
|
"views" => {
|
35
35
|
'all' => {
|
36
|
-
'map' => "
|
37
|
-
|
36
|
+
'map' => "function(doc) {
|
37
|
+
if (doc['couchrest-type'] == '#{self.to_s}') {
|
38
|
+
emit(doc['_id'],1);
|
39
|
+
}
|
40
|
+
}"
|
38
41
|
}
|
39
42
|
}
|
40
43
|
}
|
@@ -27,7 +27,7 @@ module CouchRest
|
|
27
27
|
class IncludeError < StandardError; end
|
28
28
|
|
29
29
|
def self.included(base)
|
30
|
-
base.class_eval <<-EOS, __FILE__, __LINE__
|
30
|
+
base.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
31
31
|
extlib_inheritable_accessor(:properties) unless self.respond_to?(:properties)
|
32
32
|
self.properties ||= []
|
33
33
|
EOS
|
@@ -36,7 +36,7 @@ module CouchRest
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def apply_defaults
|
39
|
-
return if self.respond_to?(:
|
39
|
+
return if self.respond_to?(:new?) && (new? == false)
|
40
40
|
return unless self.class.respond_to?(:properties)
|
41
41
|
return if self.class.properties.empty?
|
42
42
|
# TODO: cache the default object
|
@@ -56,51 +56,79 @@ module CouchRest
|
|
56
56
|
def cast_keys
|
57
57
|
return unless self.class.properties
|
58
58
|
self.class.properties.each do |property|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
59
|
+
cast_property(property)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def cast_property(property, assigned=false)
|
64
|
+
return unless property.casted
|
65
|
+
key = self.has_key?(property.name) ? property.name : property.name.to_sym
|
66
|
+
# Don't cast the property unless it has a value
|
67
|
+
return unless self[key]
|
68
|
+
if property.type.is_a?(Array)
|
69
|
+
klass = ::CouchRest.constantize(property.type[0])
|
70
|
+
arr = self[key].dup.collect do |value|
|
71
|
+
unless value.instance_of?(klass)
|
72
|
+
value = convert_property_value(property, klass, value)
|
71
73
|
end
|
74
|
+
associate_casted_to_parent(value, assigned)
|
75
|
+
value
|
76
|
+
end
|
77
|
+
self[key] = klass != String ? CastedArray.new(arr) : arr
|
78
|
+
self[key].casted_by = self if self[key].respond_to?(:casted_by)
|
79
|
+
else
|
80
|
+
if property.type == 'boolean'
|
81
|
+
klass = TrueClass
|
72
82
|
else
|
73
|
-
|
74
|
-
|
75
|
-
# Using custom time parsing method because Ruby's default method is toooo slow
|
76
|
-
#self[key].is_a?(String) ? Time.mktime_with_offset(self[key].dup) : self[key]
|
77
|
-
self[key].is_a?(String) ? Time.parse(self[key].dup) : self[key]
|
78
|
-
# Float instances don't get initialized with #new
|
79
|
-
elsif ((property.init_method == 'new') && target == 'Float')
|
80
|
-
cast_float(self[key])
|
81
|
-
# 'boolean' type is simply used to generate a property? accessor method
|
82
|
-
elsif ((property.init_method == 'new') && target == 'boolean')
|
83
|
-
self[key]
|
84
|
-
else
|
85
|
-
# Let people use :send as a Time parse arg
|
86
|
-
klass = ::CouchRest.constantize(target)
|
87
|
-
klass.send(property.init_method, self[key].dup)
|
88
|
-
end
|
89
|
-
self[property.name].casted_by = self if self[property.name].respond_to?(:casted_by)
|
90
|
-
end
|
83
|
+
klass = ::CouchRest.constantize(property.type)
|
84
|
+
end
|
91
85
|
|
92
|
-
|
93
|
-
|
94
|
-
def cast_float(value)
|
95
|
-
begin
|
96
|
-
Float(value)
|
97
|
-
rescue
|
98
|
-
value
|
86
|
+
unless self[key].instance_of?(klass)
|
87
|
+
self[key] = convert_property_value(property, klass, self[property.name])
|
99
88
|
end
|
89
|
+
associate_casted_to_parent(self[property.name], assigned)
|
100
90
|
end
|
101
91
|
|
102
92
|
end
|
103
93
|
|
94
|
+
def associate_casted_to_parent(casted, assigned)
|
95
|
+
casted.casted_by = self if casted.respond_to?(:casted_by)
|
96
|
+
casted.document_saved = true if !assigned && casted.respond_to?(:document_saved)
|
97
|
+
end
|
98
|
+
|
99
|
+
def convert_property_value(property, klass, value)
|
100
|
+
if ((property.init_method == 'new') && klass == Time)
|
101
|
+
# Using custom time parsing method because Ruby's default method is toooo slow
|
102
|
+
#value.is_a?(String) ? Time.mktime_with_offset(value.dup) : value
|
103
|
+
# This fast method doesn't work 100% of the time...
|
104
|
+
# I get TypeError: no implicit conversion from nil to integer (line: 17)
|
105
|
+
self[key].is_a?(String) ? Time.parse(self[key].dup) : self[key]
|
106
|
+
# Float instances don't get initialized with #new
|
107
|
+
elsif ((property.init_method == 'new') && klass == Float)
|
108
|
+
cast_float(value)
|
109
|
+
# 'boolean' type is simply used to generate a property? accessor method
|
110
|
+
elsif ((property.init_method == 'new') && klass == TrueClass)
|
111
|
+
value
|
112
|
+
else
|
113
|
+
klass.send(property.init_method, value.dup)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def cast_property_by_name(property_name)
|
118
|
+
return unless self.class.properties
|
119
|
+
property = self.class.properties.detect{|property| property.name == property_name}
|
120
|
+
return unless property
|
121
|
+
cast_property(property, true)
|
122
|
+
end
|
123
|
+
|
124
|
+
def cast_float(value)
|
125
|
+
begin
|
126
|
+
Float(value)
|
127
|
+
rescue
|
128
|
+
value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
104
132
|
module ClassMethods
|
105
133
|
|
106
134
|
def property(name, options={})
|
@@ -126,7 +154,7 @@ module CouchRest
|
|
126
154
|
# defines the getter for the property (and optional aliases)
|
127
155
|
def create_property_getter(property)
|
128
156
|
# meth = property.name
|
129
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
157
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
130
158
|
def #{property.name}
|
131
159
|
self['#{property.name}']
|
132
160
|
end
|
@@ -145,7 +173,7 @@ module CouchRest
|
|
145
173
|
end
|
146
174
|
|
147
175
|
if property.alias
|
148
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
176
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
149
177
|
alias #{property.alias.to_sym} #{property.name.to_sym}
|
150
178
|
EOS
|
151
179
|
end
|
@@ -153,16 +181,17 @@ module CouchRest
|
|
153
181
|
|
154
182
|
# defines the setter for the property (and optional aliases)
|
155
183
|
def create_property_setter(property)
|
156
|
-
|
184
|
+
property_name = property.name
|
157
185
|
class_eval <<-EOS
|
158
|
-
def #{
|
159
|
-
self['#{
|
186
|
+
def #{property_name}=(value)
|
187
|
+
self['#{property_name}'] = value
|
188
|
+
cast_property_by_name('#{property_name}')
|
160
189
|
end
|
161
190
|
EOS
|
162
191
|
|
163
192
|
if property.alias
|
164
193
|
class_eval <<-EOS
|
165
|
-
alias #{property.alias.to_sym}= #{
|
194
|
+
alias #{property.alias.to_sym}= #{property_name.to_sym}=
|
166
195
|
EOS
|
167
196
|
end
|
168
197
|
end
|
@@ -50,7 +50,10 @@ module CouchRest
|
|
50
50
|
|
51
51
|
def self.included(base)
|
52
52
|
base.extlib_inheritable_accessor(:auto_validation)
|
53
|
-
base.class_eval <<-EOS, __FILE__, __LINE__
|
53
|
+
base.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
54
|
+
# Callbacks
|
55
|
+
define_callbacks :validate
|
56
|
+
|
54
57
|
# Turn off auto validation by default
|
55
58
|
self.auto_validation ||= false
|
56
59
|
|
@@ -71,9 +74,10 @@ module CouchRest
|
|
71
74
|
EOS
|
72
75
|
|
73
76
|
base.extend(ClassMethods)
|
74
|
-
base.class_eval <<-EOS, __FILE__, __LINE__
|
77
|
+
base.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
78
|
+
define_callbacks :validate
|
75
79
|
if method_defined?(:_run_save_callbacks)
|
76
|
-
|
80
|
+
set_callback :save, :before, :check_validations
|
77
81
|
end
|
78
82
|
EOS
|
79
83
|
base.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
@@ -115,8 +119,7 @@ module CouchRest
|
|
115
119
|
# Check if a resource is valid in a given context
|
116
120
|
#
|
117
121
|
def valid?(context = :default)
|
118
|
-
|
119
|
-
result && validate_casted_arrays
|
122
|
+
recursive_valid?(self, context, true)
|
120
123
|
end
|
121
124
|
|
122
125
|
# checking on casted objects
|
@@ -133,29 +136,24 @@ module CouchRest
|
|
133
136
|
result
|
134
137
|
end
|
135
138
|
|
136
|
-
# Begin a recursive walk of the model checking validity
|
137
|
-
#
|
138
|
-
def all_valid?(context = :default)
|
139
|
-
recursive_valid?(self, context, true)
|
140
|
-
end
|
141
|
-
|
142
139
|
# Do recursive validity checking
|
143
140
|
#
|
144
141
|
def recursive_valid?(target, context, state)
|
145
142
|
valid = state
|
146
|
-
target.
|
147
|
-
|
148
|
-
|
149
|
-
valid = valid && recursive_valid?(ivar_value, context, valid)
|
150
|
-
elsif ivar_value.respond_to?(:each)
|
151
|
-
ivar_value.each do |item|
|
143
|
+
target.each do |key, prop|
|
144
|
+
if prop.is_a?(Array)
|
145
|
+
prop.each do |item|
|
152
146
|
if item.validatable?
|
153
|
-
valid =
|
147
|
+
valid = recursive_valid?(item, context, valid) && valid
|
154
148
|
end
|
155
149
|
end
|
150
|
+
elsif prop.validatable?
|
151
|
+
valid = recursive_valid?(prop, context, valid) && valid
|
156
152
|
end
|
157
153
|
end
|
158
|
-
|
154
|
+
target._run_validate_callbacks do
|
155
|
+
target.class.validators.execute(context, target) && valid
|
156
|
+
end
|
159
157
|
end
|
160
158
|
|
161
159
|
|
@@ -212,21 +210,12 @@ module CouchRest
|
|
212
210
|
def create_context_instance_methods(context)
|
213
211
|
name = "valid_for_#{context.to_s}?" # valid_for_signup?
|
214
212
|
if !self.instance_methods.include?(name)
|
215
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
213
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
216
214
|
def #{name} # def valid_for_signup?
|
217
215
|
valid?('#{context.to_s}'.to_sym) # valid?('signup'.to_sym)
|
218
216
|
end # end
|
219
217
|
EOS
|
220
218
|
end
|
221
|
-
|
222
|
-
all = "all_valid_for_#{context.to_s}?" # all_valid_for_signup?
|
223
|
-
if !self.instance_methods.include?(all)
|
224
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
225
|
-
def #{all} # def all_valid_for_signup?
|
226
|
-
all_valid?('#{context.to_s}'.to_sym) # all_valid?('signup'.to_sym)
|
227
|
-
end # end
|
228
|
-
EOS
|
229
|
-
end
|
230
219
|
end
|
231
220
|
|
232
221
|
# Create a new validator of the given klazz and push it onto the
|
@@ -5,8 +5,10 @@ module CouchRest
|
|
5
5
|
module CastedModel
|
6
6
|
|
7
7
|
def self.included(base)
|
8
|
+
base.send(:include, ::CouchRest::Callbacks)
|
8
9
|
base.send(:include, ::CouchRest::Mixins::Properties)
|
9
10
|
base.send(:attr_accessor, :casted_by)
|
11
|
+
base.send(:attr_accessor, :document_saved)
|
10
12
|
end
|
11
13
|
|
12
14
|
def initialize(keys={})
|
@@ -26,5 +28,31 @@ module CouchRest
|
|
26
28
|
def [] key
|
27
29
|
super(key.to_s)
|
28
30
|
end
|
31
|
+
|
32
|
+
# Gets a reference to the top level extended
|
33
|
+
# document that a model is saved inside of
|
34
|
+
def base_doc
|
35
|
+
return nil unless @casted_by
|
36
|
+
@casted_by.base_doc
|
37
|
+
end
|
38
|
+
|
39
|
+
# False if the casted model has already
|
40
|
+
# been saved in the containing document
|
41
|
+
def new?
|
42
|
+
!@document_saved
|
43
|
+
end
|
44
|
+
alias :new_record? :new?
|
45
|
+
|
46
|
+
# Sets the attributes from a hash
|
47
|
+
def update_attributes_without_saving(hash)
|
48
|
+
hash.each do |k, v|
|
49
|
+
raise NoMethodError, "#{k}= method not available, use property :#{k}" unless self.respond_to?("#{k}=")
|
50
|
+
end
|
51
|
+
hash.each do |k, v|
|
52
|
+
self.send("#{k}=",v)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
alias :attributes= :update_attributes_without_saving
|
56
|
+
|
29
57
|
end
|
30
|
-
end
|
58
|
+
end
|
@@ -21,7 +21,7 @@ module CouchRest
|
|
21
21
|
|
22
22
|
def self.inherited(subklass)
|
23
23
|
subklass.send(:include, CouchRest::Mixins::Properties)
|
24
|
-
subklass.class_eval <<-EOS, __FILE__, __LINE__
|
24
|
+
subklass.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
25
25
|
def self.inherited(subklass)
|
26
26
|
subklass.properties = self.properties.dup
|
27
27
|
end
|
@@ -33,10 +33,10 @@ module CouchRest
|
|
33
33
|
attr_accessor :casted_by
|
34
34
|
|
35
35
|
# Callbacks
|
36
|
-
define_callbacks :create
|
37
|
-
define_callbacks :save
|
38
|
-
define_callbacks :update
|
39
|
-
define_callbacks :destroy
|
36
|
+
define_callbacks :create, "result == :halt"
|
37
|
+
define_callbacks :save, "result == :halt"
|
38
|
+
define_callbacks :update, "result == :halt"
|
39
|
+
define_callbacks :destroy, "result == :halt"
|
40
40
|
|
41
41
|
def initialize(passed_keys={})
|
42
42
|
apply_defaults # defined in CouchRest::Mixins::Properties
|
@@ -76,17 +76,17 @@ module CouchRest
|
|
76
76
|
# on the document whenever saving occurs. CouchRest uses a pretty
|
77
77
|
# decent time format by default. See Time#to_json
|
78
78
|
def self.timestamps!
|
79
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
79
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
80
80
|
property(:updated_at, :read_only => true, :cast_as => 'Time', :auto_validation => false)
|
81
81
|
property(:created_at, :read_only => true, :cast_as => 'Time', :auto_validation => false)
|
82
82
|
|
83
|
-
|
83
|
+
set_callback :save, :before do |object|
|
84
84
|
object['updated_at'] = Time.now
|
85
|
-
object['created_at'] = object['updated_at'] if object.
|
85
|
+
object['created_at'] = object['updated_at'] if object.new?
|
86
86
|
end
|
87
87
|
EOS
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
# Name a method that will be called before the document is first saved,
|
91
91
|
# which returns a string to be used for the document's <tt>_id</tt>.
|
92
92
|
# Because CouchDB enforces a constraint that each id must be unique,
|
@@ -128,17 +128,36 @@ module CouchRest
|
|
128
128
|
self.class.properties
|
129
129
|
end
|
130
130
|
|
131
|
+
# Gets a reference to the actual document in the DB
|
132
|
+
# Calls up to the next document if there is one,
|
133
|
+
# Otherwise we're at the top and we return self
|
134
|
+
def base_doc
|
135
|
+
return self if base_doc?
|
136
|
+
@casted_by.base_doc
|
137
|
+
end
|
138
|
+
|
139
|
+
# Checks if we're the top document
|
140
|
+
def base_doc?
|
141
|
+
!@casted_by
|
142
|
+
end
|
143
|
+
|
131
144
|
# Takes a hash as argument, and applies the values by using writer methods
|
132
145
|
# for each key. It doesn't save the document at the end. Raises a NoMethodError if the corresponding methods are
|
133
146
|
# missing. In case of error, no attributes are changed.
|
134
147
|
def update_attributes_without_saving(hash)
|
135
|
-
|
148
|
+
# remove attributes that cannot be updated, silently ignoring them
|
149
|
+
# which matches Rails behavior when, for instance, setting created_at.
|
150
|
+
# make a copy, we don't want to change arguments
|
151
|
+
attrs = hash.dup
|
152
|
+
%w[_id _rev created_at updated_at].each {|attr| attrs.delete(attr)}
|
153
|
+
attrs.each do |k, v|
|
136
154
|
raise NoMethodError, "#{k}= method not available, use property :#{k}" unless self.respond_to?("#{k}=")
|
137
155
|
end
|
138
|
-
|
156
|
+
attrs.each do |k, v|
|
139
157
|
self.send("#{k}=",v)
|
140
158
|
end
|
141
159
|
end
|
160
|
+
alias :attributes= :update_attributes_without_saving
|
142
161
|
|
143
162
|
# Takes a hash as argument, and applies the values by using writer methods
|
144
163
|
# for each key. Raises a NoMethodError if the corresponding methods are
|
@@ -149,7 +168,8 @@ module CouchRest
|
|
149
168
|
end
|
150
169
|
|
151
170
|
# for compatibility with old-school frameworks
|
152
|
-
alias :new_record? :
|
171
|
+
alias :new_record? :new?
|
172
|
+
alias :new_document? :new?
|
153
173
|
|
154
174
|
# Trigger the callbacks (before, after, around)
|
155
175
|
# and create the document
|
@@ -170,7 +190,7 @@ module CouchRest
|
|
170
190
|
# unlike save, create returns the newly created document
|
171
191
|
def create_without_callbacks(bulk =false)
|
172
192
|
raise ArgumentError, "a document requires a database to be created to (The document or the #{self.class} default database were not set)" unless database
|
173
|
-
set_unique_id if
|
193
|
+
set_unique_id if new? && self.respond_to?(:set_unique_id)
|
174
194
|
result = database.save_doc(self, bulk)
|
175
195
|
(result["ok"] == true) ? self : false
|
176
196
|
end
|
@@ -185,7 +205,7 @@ module CouchRest
|
|
185
205
|
# only if the document isn't new
|
186
206
|
def update(bulk = false)
|
187
207
|
caught = catch(:halt) do
|
188
|
-
if self.
|
208
|
+
if self.new?
|
189
209
|
save(bulk)
|
190
210
|
else
|
191
211
|
_run_update_callbacks do
|
@@ -201,7 +221,7 @@ module CouchRest
|
|
201
221
|
# and save the document
|
202
222
|
def save(bulk = false)
|
203
223
|
caught = catch(:halt) do
|
204
|
-
if self.
|
224
|
+
if self.new?
|
205
225
|
_run_save_callbacks do
|
206
226
|
save_without_callbacks(bulk)
|
207
227
|
end
|
@@ -215,9 +235,10 @@ module CouchRest
|
|
215
235
|
# Returns a boolean value
|
216
236
|
def save_without_callbacks(bulk = false)
|
217
237
|
raise ArgumentError, "a document requires a database to be saved to (The document or the #{self.class} default database were not set)" unless database
|
218
|
-
set_unique_id if
|
238
|
+
set_unique_id if new? && self.respond_to?(:set_unique_id)
|
219
239
|
result = database.save_doc(self, bulk)
|
220
|
-
|
240
|
+
mark_as_saved
|
241
|
+
true
|
221
242
|
end
|
222
243
|
|
223
244
|
# Saves the document to the db using save. Raises an exception
|
@@ -242,5 +263,22 @@ module CouchRest
|
|
242
263
|
end
|
243
264
|
end
|
244
265
|
|
266
|
+
protected
|
267
|
+
|
268
|
+
# Set document_saved flag on all casted models to true
|
269
|
+
def mark_as_saved
|
270
|
+
self.each do |key, prop|
|
271
|
+
if prop.is_a?(Array)
|
272
|
+
prop.each do |item|
|
273
|
+
if item.respond_to?(:document_saved)
|
274
|
+
item.send(:document_saved=, true)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
elsif prop.respond_to?(:document_saved)
|
278
|
+
prop.send(:document_saved=, true)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
245
283
|
end
|
246
284
|
end
|