couchrest_model 1.0.0.beta7
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/LICENSE +176 -0
- data/README.md +320 -0
- data/Rakefile +71 -0
- data/THANKS.md +19 -0
- data/examples/model/example.rb +144 -0
- data/history.txt +180 -0
- data/lib/couchrest/model.rb +10 -0
- data/lib/couchrest/model/associations.rb +207 -0
- data/lib/couchrest/model/attribute_protection.rb +74 -0
- data/lib/couchrest/model/attributes.rb +75 -0
- data/lib/couchrest/model/base.rb +111 -0
- data/lib/couchrest/model/callbacks.rb +27 -0
- data/lib/couchrest/model/casted_array.rb +39 -0
- data/lib/couchrest/model/casted_model.rb +68 -0
- data/lib/couchrest/model/class_proxy.rb +122 -0
- data/lib/couchrest/model/collection.rb +260 -0
- data/lib/couchrest/model/design_doc.rb +126 -0
- data/lib/couchrest/model/document_queries.rb +82 -0
- data/lib/couchrest/model/errors.rb +23 -0
- data/lib/couchrest/model/extended_attachments.rb +73 -0
- data/lib/couchrest/model/persistence.rb +141 -0
- data/lib/couchrest/model/properties.rb +144 -0
- data/lib/couchrest/model/property.rb +96 -0
- data/lib/couchrest/model/support/couchrest.rb +19 -0
- data/lib/couchrest/model/support/hash.rb +9 -0
- data/lib/couchrest/model/typecast.rb +170 -0
- data/lib/couchrest/model/validations.rb +68 -0
- data/lib/couchrest/model/validations/casted_model.rb +14 -0
- data/lib/couchrest/model/validations/locale/en.yml +5 -0
- data/lib/couchrest/model/validations/uniqueness.rb +45 -0
- data/lib/couchrest/model/views.rb +167 -0
- data/lib/couchrest_model.rb +56 -0
- data/spec/couchrest/assocations_spec.rb +213 -0
- data/spec/couchrest/attachment_spec.rb +148 -0
- data/spec/couchrest/attribute_protection_spec.rb +153 -0
- data/spec/couchrest/base_spec.rb +463 -0
- data/spec/couchrest/casted_model_spec.rb +424 -0
- data/spec/couchrest/casted_spec.rb +75 -0
- data/spec/couchrest/class_proxy_spec.rb +132 -0
- data/spec/couchrest/inherited_spec.rb +40 -0
- data/spec/couchrest/persistence_spec.rb +409 -0
- data/spec/couchrest/property_spec.rb +804 -0
- data/spec/couchrest/subclass_spec.rb +99 -0
- data/spec/couchrest/validations.rb +73 -0
- data/spec/couchrest/view_spec.rb +463 -0
- data/spec/fixtures/attachments/README +3 -0
- data/spec/fixtures/attachments/couchdb.png +0 -0
- data/spec/fixtures/attachments/test.html +11 -0
- data/spec/fixtures/base.rb +139 -0
- data/spec/fixtures/more/article.rb +35 -0
- data/spec/fixtures/more/card.rb +17 -0
- data/spec/fixtures/more/cat.rb +19 -0
- data/spec/fixtures/more/course.rb +25 -0
- data/spec/fixtures/more/event.rb +8 -0
- data/spec/fixtures/more/invoice.rb +14 -0
- data/spec/fixtures/more/person.rb +9 -0
- data/spec/fixtures/more/question.rb +7 -0
- data/spec/fixtures/more/service.rb +10 -0
- data/spec/fixtures/more/user.rb +22 -0
- data/spec/fixtures/views/lib.js +3 -0
- data/spec/fixtures/views/test_view/lib.js +3 -0
- data/spec/fixtures/views/test_view/only-map.js +4 -0
- data/spec/fixtures/views/test_view/test-map.js +3 -0
- data/spec/fixtures/views/test_view/test-reduce.js +3 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +48 -0
- data/utils/remap.rb +27 -0
- data/utils/subset.rb +30 -0
- metadata +232 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
# require File.join(File.dirname(__FILE__), "couchrest", "extended_document")
|
3
|
+
|
4
|
+
gem 'couchrest'
|
5
|
+
|
6
|
+
require 'couchrest'
|
7
|
+
|
8
|
+
require 'active_support/core_ext'
|
9
|
+
require 'active_support/json'
|
10
|
+
require 'active_model'
|
11
|
+
require "active_model/callbacks"
|
12
|
+
require "active_model/conversion"
|
13
|
+
require "active_model/deprecated_error_methods"
|
14
|
+
require "active_model/errors"
|
15
|
+
require "active_model/naming"
|
16
|
+
require "active_model/serialization"
|
17
|
+
require "active_model/translation"
|
18
|
+
require "active_model/validator"
|
19
|
+
require "active_model/validations"
|
20
|
+
require 'mime/types'
|
21
|
+
require "enumerator"
|
22
|
+
require "time"
|
23
|
+
require 'digest/md5'
|
24
|
+
|
25
|
+
require 'bigdecimal' # used in typecast
|
26
|
+
require 'bigdecimal/util' # used in typecast
|
27
|
+
|
28
|
+
require 'couchrest/model'
|
29
|
+
require 'couchrest/model/errors'
|
30
|
+
require "couchrest/model/persistence"
|
31
|
+
require "couchrest/model/typecast"
|
32
|
+
require "couchrest/model/property"
|
33
|
+
require "couchrest/model/casted_array"
|
34
|
+
require "couchrest/model/properties"
|
35
|
+
require "couchrest/model/validations"
|
36
|
+
require "couchrest/model/callbacks"
|
37
|
+
require "couchrest/model/document_queries"
|
38
|
+
require "couchrest/model/views"
|
39
|
+
require "couchrest/model/design_doc"
|
40
|
+
require "couchrest/model/extended_attachments"
|
41
|
+
require "couchrest/model/class_proxy"
|
42
|
+
require "couchrest/model/collection"
|
43
|
+
require "couchrest/model/attribute_protection"
|
44
|
+
require "couchrest/model/attributes"
|
45
|
+
require "couchrest/model/associations"
|
46
|
+
|
47
|
+
# Monkey patches applied to couchrest
|
48
|
+
require "couchrest/model/support/couchrest"
|
49
|
+
require "couchrest/model/support/hash"
|
50
|
+
|
51
|
+
# Base libraries
|
52
|
+
require "couchrest/model/casted_model"
|
53
|
+
require "couchrest/model/base"
|
54
|
+
|
55
|
+
# Add rails support *after* everything has loaded
|
56
|
+
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
3
|
+
|
4
|
+
class Client < CouchRest::Model::Base
|
5
|
+
use_database DB
|
6
|
+
|
7
|
+
property :name
|
8
|
+
property :tax_code
|
9
|
+
end
|
10
|
+
|
11
|
+
class SaleEntry < CouchRest::Model::Base
|
12
|
+
use_database DB
|
13
|
+
|
14
|
+
property :description
|
15
|
+
property :price
|
16
|
+
end
|
17
|
+
|
18
|
+
class SaleInvoice < CouchRest::Model::Base
|
19
|
+
use_database DB
|
20
|
+
|
21
|
+
belongs_to :client
|
22
|
+
belongs_to :alternate_client, :class_name => 'Client', :foreign_key => 'alt_client_id'
|
23
|
+
|
24
|
+
collection_of :entries, :class_name => 'SaleEntry'
|
25
|
+
|
26
|
+
property :date, Date
|
27
|
+
property :price, Integer
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
describe "Assocations" do
|
32
|
+
|
33
|
+
describe "of type belongs to" do
|
34
|
+
|
35
|
+
before :each do
|
36
|
+
@invoice = SaleInvoice.create(:price => "sam", :price => 2000)
|
37
|
+
@client = Client.create(:name => "Sam Lown")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should create a foreign key property with setter and getter" do
|
41
|
+
@invoice.properties.find{|p| p.name == 'client_id'}.should_not be_nil
|
42
|
+
@invoice.respond_to?(:client_id).should be_true
|
43
|
+
@invoice.respond_to?("client_id=").should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should set the property and provide object when set" do
|
47
|
+
@invoice.client = @client
|
48
|
+
@invoice.client_id.should eql(@client.id)
|
49
|
+
@invoice.client.should eql(@client)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should set the attribute, save and return" do
|
53
|
+
@invoice.client = @client
|
54
|
+
@invoice.save
|
55
|
+
@invoice = SaleInvoice.get(@invoice.id)
|
56
|
+
@invoice.client.id.should eql(@client.id)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should remove the association if nil is provided" do
|
60
|
+
@invoice.client = @client
|
61
|
+
@invoice.client = nil
|
62
|
+
@invoice.client_id.should be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not try to search for association if foreign_key is nil" do
|
66
|
+
@invoice.client_id = nil
|
67
|
+
Client.should_not_receive(:get)
|
68
|
+
@invoice.client
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should raise error if class name does not exist" do
|
72
|
+
lambda {
|
73
|
+
class TestBadAssoc < CouchRest::Model::Base
|
74
|
+
belongs_to :test_bad_item
|
75
|
+
end
|
76
|
+
}.should raise_error
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should allow override of foreign key" do
|
80
|
+
@invoice.respond_to?(:alternate_client).should be_true
|
81
|
+
@invoice.respond_to?("alternate_client=").should be_true
|
82
|
+
@invoice.properties.find{|p| p.name == 'alt_client_id'}.should_not be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should allow override of foreign key and save" do
|
86
|
+
@invoice.alternate_client = @client
|
87
|
+
@invoice.save
|
88
|
+
@invoice = SaleInvoice.get(@invoice.id)
|
89
|
+
@invoice.alternate_client.id.should eql(@client.id)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "of type collection_of" do
|
95
|
+
|
96
|
+
before(:each) do
|
97
|
+
@invoice = SaleInvoice.create(:price => "sam", :price => 2000)
|
98
|
+
@entries = [
|
99
|
+
SaleEntry.create(:description => 'test line 1', :price => 500),
|
100
|
+
SaleEntry.create(:description => 'test line 2', :price => 500),
|
101
|
+
SaleEntry.create(:description => 'test line 3', :price => 1000)
|
102
|
+
]
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should create an associated property and collection proxy" do
|
106
|
+
@invoice.respond_to?('entry_ids')
|
107
|
+
@invoice.respond_to?('entry_ids=')
|
108
|
+
@invoice.entries.class.should eql(::CouchRest::CollectionOfProxy)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should allow replacement of objects" do
|
112
|
+
@invoice.entries = @entries
|
113
|
+
@invoice.entries.length.should eql(3)
|
114
|
+
@invoice.entry_ids.length.should eql(3)
|
115
|
+
@invoice.entries.first.should eql(@entries.first)
|
116
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should allow ids to be set directly and load entries" do
|
120
|
+
@invoice.entry_ids = @entries.collect{|i| i.id}
|
121
|
+
@invoice.entries.length.should eql(3)
|
122
|
+
@invoice.entries.first.should eql(@entries.first)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should replace collection if ids replaced" do
|
126
|
+
@invoice.entry_ids = @entries.collect{|i| i.id}
|
127
|
+
@invoice.entries.length.should eql(3) # load once
|
128
|
+
@invoice.entry_ids = @entries[0..1].collect{|i| i.id}
|
129
|
+
@invoice.entries.length.should eql(2)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should allow forced collection update if ids changed" do
|
133
|
+
@invoice.entry_ids = @entries[0..1].collect{|i| i.id}
|
134
|
+
@invoice.entries.length.should eql(2) # load once
|
135
|
+
@invoice.entry_ids << @entries[2].id
|
136
|
+
@invoice.entry_ids.length.should eql(3)
|
137
|
+
@invoice.entries.length.should eql(2) # cached!
|
138
|
+
@invoice.entries(true).length.should eql(3)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should empty arrays when nil collection provided" do
|
142
|
+
@invoice.entries = @entries
|
143
|
+
@invoice.entries = nil
|
144
|
+
@invoice.entry_ids.should be_empty
|
145
|
+
@invoice.entries.should be_empty
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should empty arrays when nil ids array provided" do
|
149
|
+
@invoice.entries = @entries
|
150
|
+
@invoice.entry_ids = nil
|
151
|
+
@invoice.entry_ids.should be_empty
|
152
|
+
@invoice.entries.should be_empty
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should ignore nil entries" do
|
156
|
+
@invoice.entries = [ nil ]
|
157
|
+
@invoice.entry_ids.should be_empty
|
158
|
+
@invoice.entries.should be_empty
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "proxy" do
|
162
|
+
|
163
|
+
it "should ensure new entries to proxy are matched" do
|
164
|
+
@invoice.entries << @entries.first
|
165
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
166
|
+
@invoice.entries.first.should eql(@entries.first)
|
167
|
+
@invoice.entries << @entries[1]
|
168
|
+
@invoice.entries.count.should eql(2)
|
169
|
+
@invoice.entry_ids.count.should eql(2)
|
170
|
+
@invoice.entry_ids.last.should eql(@entries[1].id)
|
171
|
+
@invoice.entries.last.should eql(@entries[1])
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should support push method" do
|
175
|
+
@invoice.entries.push(@entries.first)
|
176
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should support []= method" do
|
180
|
+
@invoice.entries[0] = @entries.first
|
181
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should support unshift method" do
|
185
|
+
@invoice.entries.unshift(@entries.first)
|
186
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
187
|
+
@invoice.entries.unshift(@entries[1])
|
188
|
+
@invoice.entry_ids.first.should eql(@entries[1].id)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should support pop method" do
|
192
|
+
@invoice.entries.push(@entries.first)
|
193
|
+
@invoice.entries.pop.should eql(@entries.first)
|
194
|
+
@invoice.entries.empty?.should be_true
|
195
|
+
@invoice.entry_ids.empty?.should be_true
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should support shift method" do
|
199
|
+
@invoice.entries.push(@entries[0])
|
200
|
+
@invoice.entries.push(@entries[1])
|
201
|
+
@invoice.entries.shift.should eql(@entries[0])
|
202
|
+
@invoice.entries.first.should eql(@entries[1])
|
203
|
+
@invoice.entry_ids.first.should eql(@entries[1].id)
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Model attachments" do
|
4
|
+
|
5
|
+
describe "#has_attachment?" do
|
6
|
+
before(:each) do
|
7
|
+
reset_test_db!
|
8
|
+
@obj = Basic.new
|
9
|
+
@obj.save.should be_true
|
10
|
+
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
11
|
+
@attachment_name = 'my_attachment'
|
12
|
+
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return false if there is no attachment' do
|
16
|
+
@obj.has_attachment?('bogus').should be_false
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should return true if there is an attachment' do
|
20
|
+
@obj.has_attachment?(@attachment_name).should be_true
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return true if an object with an attachment is reloaded' do
|
24
|
+
@obj.save.should be_true
|
25
|
+
reloaded_obj = Basic.get(@obj.id)
|
26
|
+
reloaded_obj.has_attachment?(@attachment_name).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return false if an attachment has been removed' do
|
30
|
+
@obj.delete_attachment(@attachment_name)
|
31
|
+
@obj.has_attachment?(@attachment_name).should be_false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "creating an attachment" do
|
36
|
+
before(:each) do
|
37
|
+
@obj = Basic.new
|
38
|
+
@obj.save.should be_true
|
39
|
+
@file_ext = File.open(FIXTURE_PATH + '/attachments/test.html')
|
40
|
+
@file_no_ext = File.open(FIXTURE_PATH + '/attachments/README')
|
41
|
+
@attachment_name = 'my_attachment'
|
42
|
+
@content_type = 'media/mp3'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should create an attachment from file with an extension" do
|
46
|
+
@obj.create_attachment(:file => @file_ext, :name => @attachment_name)
|
47
|
+
@obj.save.should be_true
|
48
|
+
reloaded_obj = Basic.get(@obj.id)
|
49
|
+
reloaded_obj['_attachments'][@attachment_name].should_not be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should create an attachment from file without an extension" do
|
53
|
+
@obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
|
54
|
+
@obj.save.should be_true
|
55
|
+
reloaded_obj = Basic.get(@obj.id)
|
56
|
+
reloaded_obj['_attachments'][@attachment_name].should_not be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should raise ArgumentError if :file is missing' do
|
60
|
+
lambda{ @obj.create_attachment(:name => @attachment_name) }.should raise_error
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should raise ArgumentError if :name is missing' do
|
64
|
+
lambda{ @obj.create_attachment(:file => @file_ext) }.should raise_error
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should set the content-type if passed' do
|
68
|
+
@obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
|
69
|
+
@obj['_attachments'][@attachment_name]['content_type'].should == @content_type
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should detect the content-type automatically" do
|
73
|
+
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
74
|
+
@obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should use name to detect the content-type automatically if no file" do
|
78
|
+
file = File.open(FIXTURE_PATH + '/attachments/couchdb.png')
|
79
|
+
file.stub!(:path).and_return("badfilname")
|
80
|
+
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
81
|
+
@obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'reading, updating, and deleting an attachment' do
|
87
|
+
before(:each) do
|
88
|
+
@obj = Basic.new
|
89
|
+
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
90
|
+
@attachment_name = 'my_attachment'
|
91
|
+
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
92
|
+
@obj.save.should be_true
|
93
|
+
@file.rewind
|
94
|
+
@content_type = 'media/mp3'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should read an attachment that exists' do
|
98
|
+
@obj.read_attachment(@attachment_name).should == @file.read
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should update an attachment that exists' do
|
102
|
+
file = File.open(FIXTURE_PATH + '/attachments/README')
|
103
|
+
@file.should_not == file
|
104
|
+
@obj.update_attachment(:file => file, :name => @attachment_name)
|
105
|
+
@obj.save
|
106
|
+
reloaded_obj = Basic.get(@obj.id)
|
107
|
+
file.rewind
|
108
|
+
reloaded_obj.read_attachment(@attachment_name).should_not == @file.read
|
109
|
+
reloaded_obj.read_attachment(@attachment_name).should == file.read
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should set the content-type if passed' do
|
113
|
+
file = File.open(FIXTURE_PATH + '/attachments/README')
|
114
|
+
@file.should_not == file
|
115
|
+
@obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
|
116
|
+
@obj['_attachments'][@attachment_name]['content_type'].should == @content_type
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should delete an attachment that exists' do
|
120
|
+
@obj.delete_attachment(@attachment_name)
|
121
|
+
@obj.save
|
122
|
+
lambda{Basic.get(@obj.id).read_attachment(@attachment_name)}.should raise_error
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#attachment_url" do
|
127
|
+
before(:each) do
|
128
|
+
@obj = Basic.new
|
129
|
+
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
130
|
+
@attachment_name = 'my_attachment'
|
131
|
+
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
132
|
+
@obj.save.should be_true
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should return nil if attachment does not exist' do
|
136
|
+
@obj.attachment_url('bogus').should be_nil
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should return the attachment URL as specified by CouchDB HttpDocumentApi' do
|
140
|
+
@obj.attachment_url(@attachment_name).should == "#{Basic.database}/#{@obj.id}/#{@attachment_name}"
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should return the attachment URI' do
|
144
|
+
@obj.attachment_uri(@attachment_name).should == "#{Basic.database.uri}/#{@obj.id}/#{@attachment_name}"
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe "Model Attributes" do
|
4
|
+
|
5
|
+
describe "no declarations" do
|
6
|
+
class NoProtection < CouchRest::Model::Base
|
7
|
+
use_database TEST_SERVER.default_database
|
8
|
+
property :name
|
9
|
+
property :phone
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not protect anything through new" do
|
13
|
+
user = NoProtection.new(:name => "will", :phone => "555-5555")
|
14
|
+
|
15
|
+
user.name.should == "will"
|
16
|
+
user.phone.should == "555-5555"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not protect anything through attributes=" do
|
20
|
+
user = NoProtection.new
|
21
|
+
user.attributes = {:name => "will", :phone => "555-5555"}
|
22
|
+
|
23
|
+
user.name.should == "will"
|
24
|
+
user.phone.should == "555-5555"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should recreate from the database properly" do
|
28
|
+
user = NoProtection.new
|
29
|
+
user.name = "will"
|
30
|
+
user.phone = "555-5555"
|
31
|
+
user.save!
|
32
|
+
|
33
|
+
user = NoProtection.get(user.id)
|
34
|
+
user.name.should == "will"
|
35
|
+
user.phone.should == "555-5555"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "Model Base", "accessible flag" do
|
40
|
+
class WithAccessible < CouchRest::Model::Base
|
41
|
+
use_database TEST_SERVER.default_database
|
42
|
+
property :name, :accessible => true
|
43
|
+
property :admin, :default => false
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should recognize accessible properties" do
|
47
|
+
props = WithAccessible.accessible_properties.map { |prop| prop.name}
|
48
|
+
props.should include("name")
|
49
|
+
props.should_not include("admin")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should protect non-accessible properties set through new" do
|
53
|
+
user = WithAccessible.new(:name => "will", :admin => true)
|
54
|
+
|
55
|
+
user.name.should == "will"
|
56
|
+
user.admin.should == false
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should protect non-accessible properties set through attributes=" do
|
60
|
+
user = WithAccessible.new
|
61
|
+
user.attributes = {:name => "will", :admin => true}
|
62
|
+
|
63
|
+
user.name.should == "will"
|
64
|
+
user.admin.should == false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "Model Base", "protected flag" do
|
69
|
+
class WithProtected < CouchRest::Model::Base
|
70
|
+
use_database TEST_SERVER.default_database
|
71
|
+
property :name
|
72
|
+
property :admin, :default => false, :protected => true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should recognize protected properties" do
|
76
|
+
props = WithProtected.protected_properties.map { |prop| prop.name}
|
77
|
+
props.should_not include("name")
|
78
|
+
props.should include("admin")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should protect non-accessible properties set through new" do
|
82
|
+
user = WithProtected.new(:name => "will", :admin => true)
|
83
|
+
|
84
|
+
user.name.should == "will"
|
85
|
+
user.admin.should == false
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should protect non-accessible properties set through attributes=" do
|
89
|
+
user = WithProtected.new
|
90
|
+
user.attributes = {:name => "will", :admin => true}
|
91
|
+
|
92
|
+
user.name.should == "will"
|
93
|
+
user.admin.should == false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "protected flag" do
|
98
|
+
class WithBoth < CouchRest::Model::Base
|
99
|
+
use_database TEST_SERVER.default_database
|
100
|
+
property :name, :accessible => true
|
101
|
+
property :admin, :default => false, :protected => true
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should raise an error when both are set" do
|
105
|
+
lambda { WithBoth.new }.should raise_error
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "from database" do
|
110
|
+
class WithProtected < CouchRest::Model::Base
|
111
|
+
use_database TEST_SERVER.default_database
|
112
|
+
property :name
|
113
|
+
property :admin, :default => false, :protected => true
|
114
|
+
view_by :name
|
115
|
+
end
|
116
|
+
|
117
|
+
before(:each) do
|
118
|
+
@user = WithProtected.new
|
119
|
+
@user.name = "will"
|
120
|
+
@user.admin = true
|
121
|
+
@user.save!
|
122
|
+
end
|
123
|
+
|
124
|
+
def verify_attrs(user)
|
125
|
+
user.name.should == "will"
|
126
|
+
user.admin.should == true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "Base#get should not strip protected attributes" do
|
130
|
+
reloaded = WithProtected.get( @user.id )
|
131
|
+
verify_attrs reloaded
|
132
|
+
end
|
133
|
+
|
134
|
+
it "Base#get! should not strip protected attributes" do
|
135
|
+
reloaded = WithProtected.get!( @user.id )
|
136
|
+
verify_attrs reloaded
|
137
|
+
end
|
138
|
+
|
139
|
+
it "Base#all should not strip protected attributes" do
|
140
|
+
# all creates a CollectionProxy
|
141
|
+
docs = WithProtected.all(:key => @user.id)
|
142
|
+
docs.size.should == 1
|
143
|
+
reloaded = docs.first
|
144
|
+
verify_attrs reloaded
|
145
|
+
end
|
146
|
+
|
147
|
+
it "views should not strip protected attributes" do
|
148
|
+
docs = WithProtected.by_name(:startkey => "will", :endkey => "will")
|
149
|
+
reloaded = docs.first
|
150
|
+
verify_attrs reloaded
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|