couchrest_model 1.1.0.beta5 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|