couchrest_model 1.1.0.beta5 → 1.1.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +9 -12
- data/VERSION +1 -1
- data/couchrest_model.gemspec +6 -6
- data/history.md +23 -0
- data/lib/couchrest/model/associations.rb +50 -54
- data/lib/couchrest/model/base.rb +10 -15
- data/lib/couchrest/model/casted_array.rb +16 -0
- data/lib/couchrest/model/class_proxy.rb +8 -1
- data/lib/couchrest/model/collection.rb +1 -0
- data/lib/couchrest/model/design_doc.rb +0 -2
- data/lib/couchrest/model/document_queries.rb +8 -8
- data/lib/couchrest/model/errors.rb +2 -0
- data/lib/couchrest/model/persistence.rb +20 -15
- data/lib/couchrest/model/properties.rb +17 -29
- data/lib/couchrest/model/property.rb +23 -7
- data/lib/couchrest/model/proxyable.rb +11 -4
- data/lib/couchrest/model/support/couchrest_database.rb +13 -0
- data/lib/couchrest/model/support/couchrest_design.rb +1 -1
- data/lib/couchrest/model/typecast.rb +1 -2
- data/lib/couchrest/model/validations/uniqueness.rb +29 -14
- data/lib/couchrest_model.rb +1 -1
- data/spec/couchrest/assocations_spec.rb +28 -1
- data/spec/couchrest/base_spec.rb +64 -26
- data/spec/couchrest/class_proxy_spec.rb +29 -0
- data/spec/couchrest/collection_spec.rb +6 -7
- data/spec/couchrest/design_doc_spec.rb +5 -1
- data/spec/couchrest/dirty_spec.rb +52 -0
- data/spec/couchrest/inherited_spec.rb +23 -30
- data/spec/couchrest/persistence_spec.rb +40 -18
- data/spec/couchrest/property_spec.rb +90 -4
- data/spec/couchrest/proxyable_spec.rb +14 -7
- data/spec/couchrest/validations_spec.rb +18 -1
- data/spec/fixtures/base.rb +4 -3
- data/spec/fixtures/more/article.rb +1 -0
- data/spec/fixtures/more/cat.rb +4 -0
- data/spec/fixtures/more/key_chain.rb +5 -0
- metadata +22 -21
@@ -3,7 +3,7 @@
|
|
3
3
|
module CouchRest
|
4
4
|
module Model
|
5
5
|
module Validations
|
6
|
-
|
6
|
+
|
7
7
|
# Validates if a field is unique
|
8
8
|
class UniquenessValidator < ActiveModel::EachValidator
|
9
9
|
|
@@ -11,29 +11,33 @@ module CouchRest
|
|
11
11
|
# or add one if necessary.
|
12
12
|
def setup(model)
|
13
13
|
@model = model
|
14
|
+
if options[:view].blank?
|
15
|
+
attributes.each do |attribute|
|
16
|
+
opts = merge_view_options(attribute)
|
17
|
+
|
18
|
+
if model.respond_to?(:has_view?) && !model.has_view?(opts[:view_name])
|
19
|
+
opts[:keys] << {:allow_nil => true}
|
20
|
+
model.view_by(*opts[:keys])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
14
24
|
end
|
15
25
|
|
16
26
|
def validate_each(document, attribute, value)
|
17
|
-
|
18
|
-
unless options[:scope].nil?
|
19
|
-
keys = (options[:scope].is_a?(Array) ? options[:scope] : [options[:scope]]) + keys
|
20
|
-
end
|
21
|
-
values = keys.map{|k| document.send(k)}
|
22
|
-
values = values.first if values.length == 1
|
27
|
+
opts = merge_view_options(attribute)
|
23
28
|
|
24
|
-
|
29
|
+
values = opts[:keys].map{|k| document.send(k)}
|
30
|
+
values = values.first if values.length == 1
|
25
31
|
|
26
32
|
model = (document.respond_to?(:model_proxy) && document.model_proxy ? document.model_proxy : @model)
|
27
33
|
# Determine the base of the search
|
28
|
-
base =
|
34
|
+
base = opts[:proxy].nil? ? model : document.instance_eval(opts[:proxy])
|
29
35
|
|
30
|
-
if base.respond_to?(:has_view?) && !base.has_view?(view_name)
|
31
|
-
raise "View #{document.class.name}.#{
|
32
|
-
keys << {:allow_nil => true}
|
33
|
-
model.view_by(*keys)
|
36
|
+
if base.respond_to?(:has_view?) && !base.has_view?(opts[:view_name])
|
37
|
+
raise "View #{document.class.name}.#{opts[:view_name]} does not exist for validation!"
|
34
38
|
end
|
35
39
|
|
36
|
-
rows = base.view(view_name, :key => values, :limit => 2, :include_docs => false)['rows']
|
40
|
+
rows = base.view(opts[:view_name], :key => values, :limit => 2, :include_docs => false)['rows']
|
37
41
|
return if rows.empty?
|
38
42
|
|
39
43
|
unless document.new?
|
@@ -47,6 +51,17 @@ module CouchRest
|
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
54
|
+
private
|
55
|
+
|
56
|
+
def merge_view_options(attr)
|
57
|
+
keys = [attr]
|
58
|
+
keys.unshift(*options[:scope]) unless options[:scope].nil?
|
59
|
+
|
60
|
+
view_name = options[:view].nil? ? "by_#{keys.join('_and_')}" : options[:view]
|
61
|
+
|
62
|
+
options.merge({:keys => keys, :view_name => view_name})
|
63
|
+
end
|
64
|
+
|
50
65
|
end
|
51
66
|
|
52
67
|
end
|
data/lib/couchrest_model.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'active_model'
|
2
2
|
require "active_model/callbacks"
|
3
3
|
require "active_model/conversion"
|
4
|
-
require "active_model/deprecated_error_methods"
|
5
4
|
require "active_model/errors"
|
6
5
|
require "active_model/naming"
|
7
6
|
require "active_model/serialization"
|
@@ -52,6 +51,7 @@ require "couchrest/model/designs/view"
|
|
52
51
|
|
53
52
|
# Monkey patches applied to couchrest
|
54
53
|
require "couchrest/model/support/couchrest_design"
|
54
|
+
require "couchrest/model/support/couchrest_database"
|
55
55
|
|
56
56
|
# Core Extensions
|
57
57
|
require "couchrest/model/core_extensions/hash"
|
@@ -101,7 +101,7 @@ describe "Assocations" do
|
|
101
101
|
it "should create an associated property and collection proxy" do
|
102
102
|
@invoice.respond_to?('entry_ids').should be_true
|
103
103
|
@invoice.respond_to?('entry_ids=').should be_true
|
104
|
-
@invoice.entries.class.should eql(::CouchRest::CollectionOfProxy)
|
104
|
+
@invoice.entries.class.should eql(::CouchRest::Model::CollectionOfProxy)
|
105
105
|
end
|
106
106
|
|
107
107
|
it "should allow replacement of objects" do
|
@@ -154,6 +154,33 @@ describe "Assocations" do
|
|
154
154
|
@invoice.entries.should be_empty
|
155
155
|
end
|
156
156
|
|
157
|
+
# Account for dirty tracking
|
158
|
+
describe "dirty tracking" do
|
159
|
+
it "should register changes on push" do
|
160
|
+
@invoice.changed?.should be_false
|
161
|
+
@invoice.entries << @entries[0]
|
162
|
+
@invoice.changed?.should be_true
|
163
|
+
end
|
164
|
+
it "should register changes on pop" do
|
165
|
+
@invoice.entries << @entries[0]
|
166
|
+
@invoice.save
|
167
|
+
@invoice.changed?.should be_false
|
168
|
+
@invoice.entries.pop
|
169
|
+
@invoice.changed?.should be_true
|
170
|
+
end
|
171
|
+
it "should register id changes on push" do
|
172
|
+
@invoice.entry_ids << @entries[0].id
|
173
|
+
@invoice.changed?.should be_true
|
174
|
+
end
|
175
|
+
it "should register id changes on pop" do
|
176
|
+
@invoice.entry_ids << @entries[0].id
|
177
|
+
@invoice.save
|
178
|
+
@invoice.changed?.should be_false
|
179
|
+
@invoice.entry_ids.pop
|
180
|
+
@invoice.changed?.should be_true
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
157
184
|
describe "proxy" do
|
158
185
|
|
159
186
|
it "should ensure new entries to proxy are matched" do
|
data/spec/couchrest/base_spec.rb
CHANGED
@@ -44,8 +44,39 @@ describe "Model Base" do
|
|
44
44
|
@obj.database.should eql('database')
|
45
45
|
end
|
46
46
|
|
47
|
+
it "should support initialization block" do
|
48
|
+
@obj = Basic.new {|b| b.database = 'database'}
|
49
|
+
@obj.database.should eql('database')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should only set defined properties" do
|
53
|
+
@doc = WithDefaultValues.new(:name => 'test', :foo => 'bar')
|
54
|
+
@doc['name'].should eql('test')
|
55
|
+
@doc['foo'].should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should set all properties with :directly_set_attributes option" do
|
59
|
+
@doc = WithDefaultValues.new({:name => 'test', :foo => 'bar'}, :directly_set_attributes => true)
|
60
|
+
@doc['name'].should eql('test')
|
61
|
+
@doc['foo'].should eql('bar')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set the model type" do
|
65
|
+
@doc = WithDefaultValues.new()
|
66
|
+
@doc[WithDefaultValues.model_type_key].should eql('WithDefaultValues')
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should call after_initialize method if available" do
|
70
|
+
@doc = WithAfterInitializeMethod.new
|
71
|
+
@doc['some_value'].should eql('value')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should call after_initialize after block" do
|
75
|
+
@doc = WithAfterInitializeMethod.new {|d| d.some_value = "foo"}
|
76
|
+
@doc['some_value'].should eql('foo')
|
77
|
+
end
|
47
78
|
end
|
48
|
-
|
79
|
+
|
49
80
|
describe "ActiveModel compatability Basic" do
|
50
81
|
|
51
82
|
before(:each) do
|
@@ -104,9 +135,23 @@ describe "Model Base" do
|
|
104
135
|
end
|
105
136
|
end
|
106
137
|
|
138
|
+
describe "#destroyed?" do
|
139
|
+
it "should be present" do
|
140
|
+
@obj.should respond_to(:destroyed?)
|
141
|
+
end
|
142
|
+
it "should return false with new object" do
|
143
|
+
@obj.destroyed?.should be_false
|
144
|
+
end
|
145
|
+
it "should return true after destroy" do
|
146
|
+
@obj.save
|
147
|
+
@obj.destroy
|
148
|
+
@obj.destroyed?.should be_true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
107
152
|
|
108
153
|
end
|
109
|
-
|
154
|
+
|
110
155
|
describe "update attributes without saving" do
|
111
156
|
before(:each) do
|
112
157
|
a = Article.get "big-bad-danger" rescue nil
|
@@ -147,7 +192,7 @@ describe "Model Base" do
|
|
147
192
|
}.should_not raise_error
|
148
193
|
@art.slug.should == "big-bad-danger"
|
149
194
|
end
|
150
|
-
|
195
|
+
|
151
196
|
#it "should not change other attributes if there is an error" do
|
152
197
|
# lambda {
|
153
198
|
# @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
|
@@ -155,7 +200,7 @@ describe "Model Base" do
|
|
155
200
|
# @art['title'].should == "big bad danger"
|
156
201
|
#end
|
157
202
|
end
|
158
|
-
|
203
|
+
|
159
204
|
describe "update attributes" do
|
160
205
|
before(:each) do
|
161
206
|
a = Article.get "big-bad-danger" rescue nil
|
@@ -170,7 +215,7 @@ describe "Model Base" do
|
|
170
215
|
loaded['title'].should == "super danger"
|
171
216
|
end
|
172
217
|
end
|
173
|
-
|
218
|
+
|
174
219
|
describe "with default" do
|
175
220
|
it "should have the default value set at initalization" do
|
176
221
|
@obj.preset.should == {:right => 10, :top_align => false}
|
@@ -227,7 +272,7 @@ describe "Model Base" do
|
|
227
272
|
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
228
273
|
WithTemplateAndUniqueID.database.bulk_delete
|
229
274
|
@tmpl = WithTemplateAndUniqueID.new
|
230
|
-
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', '
|
275
|
+
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'slug' => '1')
|
231
276
|
end
|
232
277
|
it "should have fields set when new" do
|
233
278
|
@tmpl.preset.should == 'value'
|
@@ -248,10 +293,10 @@ describe "Model Base" do
|
|
248
293
|
before(:all) do
|
249
294
|
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
250
295
|
WithTemplateAndUniqueID.database.bulk_delete
|
251
|
-
WithTemplateAndUniqueID.new('
|
252
|
-
WithTemplateAndUniqueID.new('
|
253
|
-
WithTemplateAndUniqueID.new('
|
254
|
-
WithTemplateAndUniqueID.new('
|
296
|
+
WithTemplateAndUniqueID.new('slug' => '1').save
|
297
|
+
WithTemplateAndUniqueID.new('slug' => '2').save
|
298
|
+
WithTemplateAndUniqueID.new('slug' => '3').save
|
299
|
+
WithTemplateAndUniqueID.new('slug' => '4').save
|
255
300
|
end
|
256
301
|
it "should find all" do
|
257
302
|
rs = WithTemplateAndUniqueID.all
|
@@ -269,9 +314,9 @@ describe "Model Base" do
|
|
269
314
|
end
|
270
315
|
|
271
316
|
it ".count should return the number of documents" do
|
272
|
-
WithTemplateAndUniqueID.new('
|
273
|
-
WithTemplateAndUniqueID.new('
|
274
|
-
WithTemplateAndUniqueID.new('
|
317
|
+
WithTemplateAndUniqueID.new('slug' => '1').save
|
318
|
+
WithTemplateAndUniqueID.new('slug' => '2').save
|
319
|
+
WithTemplateAndUniqueID.new('slug' => '3').save
|
275
320
|
|
276
321
|
WithTemplateAndUniqueID.count.should == 3
|
277
322
|
end
|
@@ -280,14 +325,14 @@ describe "Model Base" do
|
|
280
325
|
describe "finding the first instance of a model" do
|
281
326
|
before(:each) do
|
282
327
|
@db = reset_test_db!
|
283
|
-
WithTemplateAndUniqueID.new('
|
284
|
-
WithTemplateAndUniqueID.new('
|
285
|
-
WithTemplateAndUniqueID.new('
|
286
|
-
WithTemplateAndUniqueID.new('
|
328
|
+
WithTemplateAndUniqueID.new('slug' => '1').save
|
329
|
+
WithTemplateAndUniqueID.new('slug' => '2').save
|
330
|
+
WithTemplateAndUniqueID.new('slug' => '3').save
|
331
|
+
WithTemplateAndUniqueID.new('slug' => '4').save
|
287
332
|
end
|
288
333
|
it "should find first" do
|
289
334
|
rs = WithTemplateAndUniqueID.first
|
290
|
-
rs['
|
335
|
+
rs['slug'].should == "1"
|
291
336
|
end
|
292
337
|
it "should return nil if no instances are found" do
|
293
338
|
WithTemplateAndUniqueID.all.each {|obj| obj.destroy }
|
@@ -365,14 +410,7 @@ describe "Model Base" do
|
|
365
410
|
end
|
366
411
|
end
|
367
412
|
|
368
|
-
|
369
|
-
it "should call after_initialize method if available" do
|
370
|
-
@doc = WithAfterInitializeMethod.new
|
371
|
-
@doc['some_value'].should eql('value')
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
describe "recursive validation on a model" do
|
413
|
+
describe "recursive validation on a model" do
|
376
414
|
before :each do
|
377
415
|
reset_test_db!
|
378
416
|
@cat = Cat.new(:name => 'Sockington')
|
@@ -123,6 +123,35 @@ describe "Proxy Class" do
|
|
123
123
|
u.respond_to?(:database).should be_false
|
124
124
|
end
|
125
125
|
end
|
126
|
+
|
127
|
+
describe "#get!" do
|
128
|
+
it "raises exception when passed a nil" do
|
129
|
+
expect { @us.get!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "raises exception when passed an empty string " do
|
133
|
+
expect { @us.get!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "raises exception when document with provided id does not exist" do
|
137
|
+
expect { @us.get!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "#find!" do
|
142
|
+
it "raises exception when passed a nil" do
|
143
|
+
expect { @us.find!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "raises exception when passed an empty string " do
|
147
|
+
expect { @us.find!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "raises exception when document with provided id does not exist" do
|
151
|
+
expect { @us.find!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
126
155
|
# Sam Lown 2010-04-07
|
127
156
|
# Removed as unclear why this should happen as before my changes
|
128
157
|
# this happend by accident, not explicitly.
|
@@ -27,21 +27,20 @@ describe "Collections" do
|
|
27
27
|
end
|
28
28
|
it "should provide a class method for paginate" do
|
29
29
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
30
|
-
:per_page => 3, :descending => true, :key => Date.today
|
30
|
+
:per_page => 3, :descending => true, :key => Date.today)
|
31
31
|
articles.size.should == 3
|
32
|
-
|
32
|
+
|
33
33
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
34
|
-
:per_page => 3, :page => 2, :descending => true, :key => Date.today
|
34
|
+
:per_page => 3, :page => 2, :descending => true, :key => Date.today)
|
35
35
|
articles.size.should == 3
|
36
|
-
|
36
|
+
|
37
37
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
38
|
-
:per_page => 3, :page => 3, :descending => true, :key => Date.today
|
38
|
+
:per_page => 3, :page => 3, :descending => true, :key => Date.today)
|
39
39
|
articles.size.should == 1
|
40
40
|
end
|
41
41
|
it "should provide a class method for paginated_each" do
|
42
42
|
options = { :design_doc => 'Article', :view_name => 'by_date',
|
43
|
-
:per_page => 3, :page => 1, :descending => true, :key => Date.today
|
44
|
-
:include_docs => true }
|
43
|
+
:per_page => 3, :page => 1, :descending => true, :key => Date.today }
|
45
44
|
Article.paginated_each(options) do |a|
|
46
45
|
a.should_not be_nil
|
47
46
|
end
|
@@ -155,6 +155,10 @@ describe "Design Documents" do
|
|
155
155
|
Article.by_date
|
156
156
|
Article.stored_design_doc['_rev'].should eql(orig)
|
157
157
|
end
|
158
|
+
it "should recreate the design doc if database deleted" do
|
159
|
+
Article.database.recreate!
|
160
|
+
lambda { Article.by_date }.should_not raise_error(RestClient::ResourceNotFound)
|
161
|
+
end
|
158
162
|
end
|
159
163
|
|
160
164
|
describe "when auto_update_design_doc false" do
|
@@ -198,7 +202,7 @@ describe "Design Documents" do
|
|
198
202
|
describe "lazily refreshing the design document" do
|
199
203
|
before(:all) do
|
200
204
|
@db = reset_test_db!
|
201
|
-
WithTemplateAndUniqueID.new('
|
205
|
+
WithTemplateAndUniqueID.new('slug' => '1').save
|
202
206
|
end
|
203
207
|
it "should not save the design doc twice" do
|
204
208
|
WithTemplateAndUniqueID.all
|
@@ -241,6 +241,14 @@ describe "Dirty" do
|
|
241
241
|
end
|
242
242
|
end
|
243
243
|
|
244
|
+
it "should report changes if an array is popped after reload" do
|
245
|
+
should_change_array do |array, obj|
|
246
|
+
obj.reload
|
247
|
+
obj.keywords.pop
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
|
244
252
|
it "should report no changes if an empty array is popped" do
|
245
253
|
should_not_change_array do |array, obj|
|
246
254
|
array.clear
|
@@ -249,6 +257,50 @@ describe "Dirty" do
|
|
249
257
|
end
|
250
258
|
end
|
251
259
|
|
260
|
+
it "should report changes on deletion from an array" do
|
261
|
+
should_change_array do |array, obj|
|
262
|
+
array << "keyword"
|
263
|
+
obj.save!
|
264
|
+
array.delete_at(0)
|
265
|
+
end
|
266
|
+
|
267
|
+
should_change_array do |array, obj|
|
268
|
+
array << "keyword"
|
269
|
+
obj.save!
|
270
|
+
array.delete("keyword")
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should report changes on deletion from an array after reload" do
|
275
|
+
should_change_array do |array, obj|
|
276
|
+
array << "keyword"
|
277
|
+
obj.save!
|
278
|
+
obj.reload
|
279
|
+
array.delete_at(0)
|
280
|
+
end
|
281
|
+
|
282
|
+
should_change_array do |array, obj|
|
283
|
+
array << "keyword"
|
284
|
+
obj.save!
|
285
|
+
obj.reload
|
286
|
+
array.delete("keyword")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should report no changes on deletion from an empty array" do
|
291
|
+
should_not_change_array do |array, obj|
|
292
|
+
array.clear
|
293
|
+
obj.save!
|
294
|
+
array.delete_at(0)
|
295
|
+
end
|
296
|
+
|
297
|
+
should_not_change_array do |array, obj|
|
298
|
+
array.clear
|
299
|
+
obj.save!
|
300
|
+
array.delete("keyword")
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
252
304
|
it "should report changes if an array is pushed" do
|
253
305
|
should_change_array do |array, obj|
|
254
306
|
array.push("keyword")
|
@@ -1,40 +1,33 @@
|
|
1
1
|
require File.expand_path('../../spec_helper', __FILE__)
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class PlainParent
|
9
|
-
class_inheritable_accessor :foo
|
10
|
-
self.foo = :bar
|
11
|
-
end
|
3
|
+
class PlainParent
|
4
|
+
class_inheritable_accessor :foo
|
5
|
+
self.foo = :bar
|
6
|
+
end
|
12
7
|
|
13
|
-
|
14
|
-
|
8
|
+
class PlainChild < PlainParent
|
9
|
+
end
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
class ExtendedParent < CouchRest::Model::Base
|
12
|
+
class_inheritable_accessor :foo
|
13
|
+
self.foo = :bar
|
14
|
+
end
|
20
15
|
|
21
|
-
|
22
|
-
|
16
|
+
class ExtendedChild < ExtendedParent
|
17
|
+
end
|
23
18
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
19
|
+
describe "Using chained inheritance without CouchRest::Model::Base" do
|
20
|
+
it "should preserve inheritable attributes" do
|
21
|
+
PlainParent.foo.should == :bar
|
22
|
+
PlainChild.foo.should == :bar
|
29
23
|
end
|
24
|
+
end
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
26
|
+
describe "Using chained inheritance with CouchRest::Model::Base" do
|
27
|
+
it "should preserve inheritable attributes" do
|
28
|
+
ExtendedParent.foo.should == :bar
|
29
|
+
ExtendedChild.foo.should == :bar
|
36
30
|
end
|
37
|
-
|
38
|
-
rescue LoadError
|
39
|
-
puts "This spec requires 'active_support/json' to be loaded"
|
40
31
|
end
|
32
|
+
|
33
|
+
|
@@ -5,6 +5,7 @@ require File.join(FIXTURE_PATH, 'more', 'cat')
|
|
5
5
|
require File.join(FIXTURE_PATH, 'more', 'article')
|
6
6
|
require File.join(FIXTURE_PATH, 'more', 'course')
|
7
7
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
8
|
+
require File.join(FIXTURE_PATH, 'more', 'event')
|
8
9
|
|
9
10
|
describe "Model Persistence" do
|
10
11
|
|
@@ -34,11 +35,11 @@ describe "Model Persistence" do
|
|
34
35
|
describe "basic saving and retrieving" do
|
35
36
|
it "should work fine" do
|
36
37
|
@obj.name = "should be easily saved and retrieved"
|
37
|
-
@obj.save
|
38
|
-
saved_obj = WithDefaultValues.get(@obj.id)
|
38
|
+
@obj.save!
|
39
|
+
saved_obj = WithDefaultValues.get!(@obj.id)
|
39
40
|
saved_obj.should_not be_nil
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
it "should parse the Time attributes automatically" do
|
43
44
|
@obj.name = "should parse the Time attributes automatically"
|
44
45
|
@obj.set_by_proc.should be_an_instance_of(Time)
|
@@ -81,6 +82,18 @@ describe "Model Persistence" do
|
|
81
82
|
article.should_not be_new
|
82
83
|
end
|
83
84
|
|
85
|
+
it "yields new instance to block before saving (#create)" do
|
86
|
+
article = Article.create{|a| a.title = 'my create init block test'}
|
87
|
+
article.title.should == 'my create init block test'
|
88
|
+
article.should_not be_new
|
89
|
+
end
|
90
|
+
|
91
|
+
it "yields new instance to block before saving (#create!)" do
|
92
|
+
article = Article.create{|a| a.title = 'my create bang init block test'}
|
93
|
+
article.title.should == 'my create bang init block test'
|
94
|
+
article.should_not be_new
|
95
|
+
end
|
96
|
+
|
84
97
|
it "should trigger the create callbacks" do
|
85
98
|
doc = WithCallBacks.create(:name => 'my other test')
|
86
99
|
doc.run_before_create.should be_true
|
@@ -210,57 +223,66 @@ describe "Model Persistence" do
|
|
210
223
|
|
211
224
|
it "should require the field" do
|
212
225
|
lambda{@templated.save}.should raise_error
|
213
|
-
@templated['
|
226
|
+
@templated['slug'] = 'very-important'
|
214
227
|
@templated.save.should be_true
|
215
228
|
end
|
216
229
|
|
217
230
|
it "should save with the id" do
|
218
|
-
@templated['
|
231
|
+
@templated['slug'] = 'very-important'
|
219
232
|
@templated.save.should be_true
|
220
233
|
t = WithTemplateAndUniqueID.get('very-important')
|
221
234
|
t.should == @templated
|
222
235
|
end
|
223
236
|
|
224
237
|
it "should not change the id on update" do
|
225
|
-
@templated['
|
238
|
+
@templated['slug'] = 'very-important'
|
226
239
|
@templated.save.should be_true
|
227
|
-
@templated['
|
240
|
+
@templated['slug'] = 'not-important'
|
228
241
|
@templated.save.should be_true
|
229
242
|
t = WithTemplateAndUniqueID.get('very-important')
|
230
243
|
t.id.should == @templated.id
|
231
244
|
end
|
232
245
|
|
233
246
|
it "should raise an error when the id is taken" do
|
234
|
-
@templated['
|
247
|
+
@templated['slug'] = 'very-important'
|
235
248
|
@templated.save.should be_true
|
236
|
-
lambda{WithTemplateAndUniqueID.new('
|
249
|
+
lambda{WithTemplateAndUniqueID.new('slug' => 'very-important').save}.should raise_error
|
237
250
|
end
|
238
251
|
|
239
252
|
it "should set the id" do
|
240
|
-
@templated['
|
253
|
+
@templated['slug'] = 'very-important'
|
241
254
|
@templated.save.should be_true
|
242
255
|
@templated.id.should == 'very-important'
|
243
256
|
end
|
244
257
|
end
|
245
|
-
|
258
|
+
|
246
259
|
describe "destroying an instance" do
|
247
260
|
before(:each) do
|
248
|
-
@dobj =
|
261
|
+
@dobj = Event.new
|
249
262
|
@dobj.save.should be_true
|
250
263
|
end
|
251
264
|
it "should return true" do
|
252
265
|
result = @dobj.destroy
|
253
266
|
result.should be_true
|
254
267
|
end
|
255
|
-
it "should
|
268
|
+
it "should make it go away" do
|
256
269
|
@dobj.destroy
|
257
|
-
@dobj.
|
258
|
-
@dobj.id.should be_nil
|
259
|
-
@dobj.save.should be_true
|
270
|
+
lambda{Basic.get!(@dobj.id)}.should raise_error(CouchRest::Model::DocumentNotFound)
|
260
271
|
end
|
261
|
-
it "should
|
272
|
+
it "should freeze the object" do
|
273
|
+
@dobj.destroy
|
274
|
+
# In Ruby 1.9.2 this raises RuntimeError, in 1.8.7 TypeError, D'OH!
|
275
|
+
lambda { @dobj.subject = "Test" }.should raise_error(StandardError)
|
276
|
+
end
|
277
|
+
it "trying to save after should fail" do
|
278
|
+
@dobj.destroy
|
279
|
+
lambda { @dobj.save }.should raise_error(StandardError)
|
280
|
+
lambda{Basic.get!(@dobj.id)}.should raise_error(CouchRest::Model::DocumentNotFound)
|
281
|
+
end
|
282
|
+
it "should make destroyed? true" do
|
283
|
+
@dobj.destroyed?.should be_false
|
262
284
|
@dobj.destroy
|
263
|
-
|
285
|
+
@dobj.destroyed?.should be_true
|
264
286
|
end
|
265
287
|
end
|
266
288
|
|