couchrest_model 1.0.0.beta7 → 1.0.0.beta8
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/README.md +25 -8
- data/Rakefile +7 -6
- data/THANKS.md +2 -0
- data/history.txt +25 -20
- data/lib/couchrest/model/base.rb +1 -1
- data/lib/couchrest/model/extended_attachments.rb +9 -5
- data/lib/couchrest/model/validations/uniqueness.rb +4 -5
- data/lib/couchrest/model/views.rb +5 -12
- data/lib/couchrest/model.rb +1 -1
- data/lib/couchrest/railtie.rb +11 -0
- data/lib/couchrest_model.rb +10 -5
- data/lib/rails/generators/couchrest_model/model/model_generator.rb +26 -0
- data/lib/rails/generators/couchrest_model/model/templates/model.rb +2 -0
- data/lib/rails/generators/couchrest_model.rb +16 -0
- data/spec/couchrest/assocations_spec.rb +15 -32
- data/spec/couchrest/attachment_spec.rb +35 -7
- data/spec/couchrest/attribute_protection_spec.rb +25 -13
- data/spec/couchrest/inherited_spec.rb +2 -2
- data/spec/couchrest/property_spec.rb +67 -55
- data/spec/couchrest/validations.rb +12 -0
- data/spec/fixtures/more/client.rb +6 -0
- data/spec/fixtures/more/sale_entry.rb +9 -0
- data/spec/fixtures/more/sale_invoice.rb +13 -0
- metadata +36 -15
- data/examples/model/example.rb +0 -144
- data/utils/remap.rb +0 -27
- data/utils/subset.rb +0 -30
data/README.md
CHANGED
@@ -13,7 +13,24 @@ CouchRest Model only supports CouchDB 0.10.0 or newer.
|
|
13
13
|
|
14
14
|
## Install
|
15
15
|
|
16
|
-
|
16
|
+
### From Gem
|
17
|
+
|
18
|
+
CouchRest Model depends on Rails 3's ActiveModel which has not yet been released. You'll need to add
|
19
|
+
`--pre` to the end of the gem install until the dependencies are stable:
|
20
|
+
|
21
|
+
$ sudo gem install couchrest_model --pre
|
22
|
+
|
23
|
+
### Bundler
|
24
|
+
|
25
|
+
If you're using bundler, just define a line similar to the following in your project's Gemfile:
|
26
|
+
|
27
|
+
gem 'couchrest_model'
|
28
|
+
|
29
|
+
You might also consider using the latest git repository. All tests should pass in the master code branch
|
30
|
+
but no guarantees!
|
31
|
+
|
32
|
+
gem 'couchrest_model', :git => 'git://github.com/couchrest/couchrest_model.git'
|
33
|
+
|
17
34
|
|
18
35
|
## General Usage
|
19
36
|
|
@@ -57,7 +74,7 @@ with a property, but a property may not have any attributes associated if none h
|
|
57
74
|
|
58
75
|
In its simplest form, a property
|
59
76
|
will only create a getter and setter passing all attribute data directly to the database. Assuming the attribute
|
60
|
-
provided responds to
|
77
|
+
provided responds to `to_json`, there will not be any problems saving it, but when loading the
|
61
78
|
data back it will either be a string, number, array, or hash:
|
62
79
|
|
63
80
|
class Cat < CouchRest::Model::Base
|
@@ -110,7 +127,7 @@ Adding the +:default+ option will ensure the attribute always has a value.
|
|
110
127
|
|
111
128
|
Defining a property as read-only will mean that its value is set only when read from the
|
112
129
|
database and that it will not have a setter method. You can however update a read-only
|
113
|
-
attribute using the
|
130
|
+
attribute using the `write_attribute` method:
|
114
131
|
|
115
132
|
class Cat < CouchRest::Model::Base
|
116
133
|
property :name, String
|
@@ -145,7 +162,7 @@ By default, the array will be ready to use from the moment the object as been in
|
|
145
162
|
@cat.nicknames == ['Buffy']
|
146
163
|
|
147
164
|
When anything other than a string is set as the class of a property, the array will be converted
|
148
|
-
into special wrapper called a CastedArray. If the child objects respond to the
|
165
|
+
into special wrapper called a CastedArray. If the child objects respond to the `casted_by` method
|
149
166
|
(such as those created with CastedModel, below) it will contain a reference to the parent.
|
150
167
|
|
151
168
|
## Casted Models
|
@@ -214,7 +231,7 @@ TODO: Document properly!
|
|
214
231
|
CouchRest Model automatically includes the new ActiveModel validations, so they should work just as the traditional Rails
|
215
232
|
validations. For more details, please see the ActiveModel::Validations documentation.
|
216
233
|
|
217
|
-
CouchRest Model adds the possibility to check the uniqueness of attributes using the
|
234
|
+
CouchRest Model adds the possibility to check the uniqueness of attributes using the `validates_uniqueness_of` class method, for example:
|
218
235
|
|
219
236
|
class Person < CouchRest::Model::Base
|
220
237
|
property :title, String
|
@@ -223,7 +240,7 @@ CouchRest Model adds the possibility to check the uniqueness of attributes using
|
|
223
240
|
end
|
224
241
|
|
225
242
|
The uniqueness validation creates a new view for the attribute or uses one that already exists. You can
|
226
|
-
specify a different view using the
|
243
|
+
specify a different view using the `:view` option, useful for when the `unique_id` is specified and
|
227
244
|
you'd like to avoid the typical RestClient Conflict error:
|
228
245
|
|
229
246
|
unique_id :code
|
@@ -307,12 +324,12 @@ CouchRest install, from the project root directory run `rake`, or `autotest`
|
|
307
324
|
|
308
325
|
API: [http://rdoc.info/projects/couchrest/couchrest_model](http://rdoc.info/projects/couchrest/couchrest_model)
|
309
326
|
|
310
|
-
Check the wiki for documentation and examples [http://wiki.github.com/couchrest/
|
327
|
+
Check the wiki for documentation and examples [http://wiki.github.com/couchrest/couchrest_model](http://wiki.github.com/couchrest/couchrest_model)
|
311
328
|
|
312
329
|
|
313
330
|
## Contact
|
314
331
|
|
315
|
-
Please post bugs, suggestions and patches to the bug tracker at [http://github.com/couchrest/
|
332
|
+
Please post bugs, suggestions and patches to the bug tracker at [http://github.com/couchrest/couchrest_model/issues](http://github.com/couchrest/couchrest_model/issues).
|
316
333
|
|
317
334
|
Follow us on Twitter: [http://twitter.com/couchrest](http://twitter.com/couchrest)
|
318
335
|
|
data/Rakefile
CHANGED
@@ -24,14 +24,15 @@ begin
|
|
24
24
|
gemspec.homepage = "http://github.com/couchrest/couchrest_model"
|
25
25
|
gemspec.authors = ["J. Chris Anderson", "Matt Aimonetti", "Marcos Tapajos", "Will Leinweber", "Sam Lown"]
|
26
26
|
gemspec.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
|
27
|
-
gemspec.files = %w( LICENSE README.md Rakefile THANKS.md history.txt couchrest.gemspec) + Dir["{examples,lib,spec
|
27
|
+
gemspec.files = %w( LICENSE README.md Rakefile THANKS.md history.txt couchrest.gemspec) + Dir["{examples,lib,spec}/**/*"] - Dir["spec/tmp"]
|
28
28
|
gemspec.has_rdoc = true
|
29
|
-
gemspec.add_dependency("couchrest", "
|
30
|
-
gemspec.add_dependency("mime-types", "
|
31
|
-
gemspec.add_dependency("activesupport", "
|
32
|
-
gemspec.add_dependency("activemodel", "
|
29
|
+
gemspec.add_dependency("couchrest", "~> 1.0.0")
|
30
|
+
gemspec.add_dependency("mime-types", "~> 1.15")
|
31
|
+
gemspec.add_dependency("activesupport", "~> 2.3.5")
|
32
|
+
gemspec.add_dependency("activemodel", "~> 3.0.0.beta4")
|
33
|
+
gemspec.add_dependency("tzinfo", "~> 0.3.22")
|
33
34
|
gemspec.version = CouchRest::Model::VERSION
|
34
|
-
gemspec.date = "
|
35
|
+
gemspec.date = Time.now.strftime("%Y-%m-%d")
|
35
36
|
gemspec.require_path = "lib"
|
36
37
|
end
|
37
38
|
rescue LoadError
|
data/THANKS.md
CHANGED
@@ -13,6 +13,8 @@ changes. A list of these people is included below.
|
|
13
13
|
* [Matt Lyon](http://mattly.tumblr.com/)
|
14
14
|
* Simon Rozet (simon /at/ rozet /dot/ name)
|
15
15
|
* [Marcos Tapajós](http://tapajos.me)
|
16
|
+
* [Sam Lown](http://github.com/samlown)
|
17
|
+
* [Will Leinweber](http://github.com/will)
|
16
18
|
|
17
19
|
Patches are welcome. The primary source for this software project is [on Github](http://github.com/couchrest/couchrest)
|
18
20
|
|
data/history.txt
CHANGED
@@ -3,12 +3,14 @@
|
|
3
3
|
* Major enhancements
|
4
4
|
|
5
5
|
* Minor enhancements
|
6
|
+
* Raise error on adding objects to "collection_of" without an id
|
7
|
+
* Allow mixing of protected and accessible properties. Any unspecified properties are now assumed to be protected by default
|
6
8
|
|
7
9
|
== CouchRest Model 1.0.0.beta7
|
8
10
|
|
9
11
|
* Major enhancements
|
10
12
|
* Renamed ExtendedDocument to CouchRest::Model
|
11
|
-
* Added initial support for simple belongs_to associations
|
13
|
+
* Added initial support for simple belongs_to associations
|
12
14
|
* Added support for basic collection_of association (unique to document databases!)
|
13
15
|
* Moved Validation to ActiveModel
|
14
16
|
* Moved Callbacks to ActiveModel
|
@@ -16,6 +18,9 @@
|
|
16
18
|
* Validation always included
|
17
19
|
* Uniqueness validation now available
|
18
20
|
|
21
|
+
* Minor enhancements
|
22
|
+
* Removed support for auto_validate! and :length on properties
|
23
|
+
|
19
24
|
|
20
25
|
== 1.0.0.beta6
|
21
26
|
|
@@ -70,7 +75,7 @@
|
|
70
75
|
* Adds support for continuous replication (sauy7)
|
71
76
|
* Automatic Type Casting (Alexander Uvarov, Sam Lown, Tim Heighes, Will Leinweber)
|
72
77
|
* Added a search method to CouchRest:Database to search the documents in a given database. (Dave Farkas, Arnaud Berthomier, John Wood)
|
73
|
-
|
78
|
+
|
74
79
|
* Minor enhancements
|
75
80
|
* Provide a description of the timeout error (John Wood)
|
76
81
|
|
@@ -99,9 +104,9 @@
|
|
99
104
|
* Adds attribute protection to properties. (Will Leinweber)
|
100
105
|
* Improved CouchRest::Database#save_doc, added "batch" mode to significantly speed up saves at cost of lower durability gurantees. (Igal Koshevoy)
|
101
106
|
* Added CouchRest::Database#bulk_save_doc and #batch_save_doc as human-friendlier wrappers around #save_doc. (Igal Koshevoy)
|
102
|
-
|
103
|
-
* Minor enhancements
|
104
|
-
|
107
|
+
|
108
|
+
* Minor enhancements
|
109
|
+
|
105
110
|
* Fix content_type handling for attachments
|
106
111
|
* Fixed a bug in the pagination code that caused it to paginate over records outside of the scope of the view parameters.(John Wood)
|
107
112
|
* Removed amount_pages calculation for the pagination collection, since it cannot be reliably calculated without a view.(John Wood)
|
@@ -120,9 +125,9 @@
|
|
120
125
|
* Major enhancements
|
121
126
|
|
122
127
|
* Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti)
|
123
|
-
|
124
|
-
* Minor enhancements
|
125
|
-
|
128
|
+
|
129
|
+
* Minor enhancements
|
130
|
+
|
126
131
|
* Added #amount_pages to a paginated result array (Matt Aimonetti)
|
127
132
|
* Ruby 1.9.2 compatible (Matt Aimonetti)
|
128
133
|
* Added a property? method for property cast as :boolean (John Wood)
|
@@ -131,14 +136,14 @@
|
|
131
136
|
* Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc)
|
132
137
|
|
133
138
|
== 0.32
|
134
|
-
|
139
|
+
|
135
140
|
* Major enhancements
|
136
141
|
|
137
142
|
* ExtendedDocument.get doesn't raise an exception anymore. If no documents are found nil is returned.
|
138
143
|
* ExtendedDocument.get! works the say #get used to work and will raise an exception if a document isn't found.
|
139
|
-
|
140
|
-
* Minor enhancements
|
141
|
-
|
144
|
+
|
145
|
+
* Minor enhancements
|
146
|
+
|
142
147
|
* Bug fix: Model.all(:keys => [1,2]) was not working (Matt Aimonetti)
|
143
148
|
* Added ValidationErrors#count in order to play nicely with Rails (Peter Wagenet)
|
144
149
|
* Bug fix: class proxy design doc refresh (Daniel Kirsh)
|
@@ -151,29 +156,29 @@
|
|
151
156
|
|
152
157
|
* Created an abstraction HTTP layer to support different http adapters (Matt Aimonetti)
|
153
158
|
* Added ExtendedDocument.create({}) and #create!({}) so you don't have to do Model.new.create (Matt Aimonetti)
|
154
|
-
|
159
|
+
|
155
160
|
* Minor enhancements
|
156
|
-
|
161
|
+
|
157
162
|
* Added an init.rb file for easy usage as a Rails plugin (Aaron Quint)
|
158
163
|
* Bug fix: pagination shouldn't die on empty results (Arnaud Berthomier)
|
159
164
|
* Optimized ExtendedDocument.count to run about 3x faster (Matt Aimonetti)
|
160
165
|
* Added Float casting (Ryan Felton & Matt Aimonetti)
|
161
166
|
|
162
167
|
== 0.30
|
163
|
-
|
168
|
+
|
164
169
|
* Major enhancements
|
165
|
-
|
170
|
+
|
166
171
|
* Added support for pagination (John Wood)
|
167
172
|
* Improved performance when initializing documents with timestamps (Matt Aimonetti)
|
168
|
-
|
173
|
+
|
169
174
|
* Minor enhancements
|
170
|
-
|
175
|
+
|
171
176
|
* Extended the API to retrieve an attachment URI (Matt Aimonetti)
|
172
177
|
* Bug fix: default value should be able to be set as false (Alexander Uvarov)
|
173
178
|
* Bug fix: validates_is_numeric should be able to properly validate a Float instance (Rob Kaufman)
|
174
179
|
* Bug fix: fixed the Timeout implementation (Seth Falcon)
|
175
|
-
|
176
|
-
|
180
|
+
|
181
|
+
|
177
182
|
---
|
178
183
|
|
179
184
|
Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest.
|
data/lib/couchrest/model/base.rb
CHANGED
@@ -39,7 +39,7 @@ module CouchRest
|
|
39
39
|
attr_accessor :casted_by
|
40
40
|
|
41
41
|
|
42
|
-
# Instantiate a new
|
42
|
+
# Instantiate a new CouchRest::Model::Base by preparing all properties
|
43
43
|
# using the provided document hash.
|
44
44
|
#
|
45
45
|
# Options supported:
|
@@ -7,11 +7,15 @@ module CouchRest
|
|
7
7
|
def create_attachment(args={})
|
8
8
|
raise ArgumentError unless args[:file] && args[:name]
|
9
9
|
return if has_attachment?(args[:name])
|
10
|
-
self['_attachments'] ||= {}
|
11
10
|
set_attachment_attr(args)
|
12
11
|
rescue ArgumentError => e
|
13
12
|
raise ArgumentError, 'You must specify :file and :name'
|
14
13
|
end
|
14
|
+
|
15
|
+
# return all attachments
|
16
|
+
def attachments
|
17
|
+
self['_attachments'] ||= {}
|
18
|
+
end
|
15
19
|
|
16
20
|
# reads the data from an attachment
|
17
21
|
def read_attachment(attachment_name)
|
@@ -30,13 +34,13 @@ module CouchRest
|
|
30
34
|
|
31
35
|
# deletes a file attachment from the current doc
|
32
36
|
def delete_attachment(attachment_name)
|
33
|
-
return unless
|
34
|
-
|
37
|
+
return unless attachments
|
38
|
+
attachments.delete attachment_name
|
35
39
|
end
|
36
40
|
|
37
41
|
# returns true if attachment_name exists
|
38
42
|
def has_attachment?(attachment_name)
|
39
|
-
!!(
|
43
|
+
!!(attachments && attachments[attachment_name] && !attachments[attachment_name].empty?)
|
40
44
|
end
|
41
45
|
|
42
46
|
# returns URL to fetch the attachment from
|
@@ -62,7 +66,7 @@ module CouchRest
|
|
62
66
|
def set_attachment_attr(args)
|
63
67
|
content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file].path)
|
64
68
|
content_type ||= (get_mime_type(args[:name]) || 'text/plain')
|
65
|
-
|
69
|
+
attachments[args[:name]] = {
|
66
70
|
'content_type' => content_type,
|
67
71
|
'data' => args[:file].read
|
68
72
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# encoding:
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
3
|
module CouchRest
|
4
4
|
module Model
|
@@ -16,15 +16,14 @@ module CouchRest
|
|
16
16
|
|
17
17
|
def validate_each(document, attribute, value)
|
18
18
|
view_name = options[:view].nil? ? "by_#{attribute}" : options[:view]
|
19
|
+
# Determine the base of the search
|
20
|
+
base = options[:proxy].nil? ? @klass : document.instance_eval(options[:proxy])
|
19
21
|
|
20
|
-
|
22
|
+
if base.respond_to?(:has_view?) && !base.has_view?(view_name)
|
21
23
|
raise "View #{document.class.name}.#{options[:view]} does not exist!" unless options[:view].nil?
|
22
24
|
@klass.view_by attribute
|
23
25
|
end
|
24
26
|
|
25
|
-
# Determine the base of the search
|
26
|
-
base = options[:proxy].nil? ? @klass : document.instance_eval(options[:proxy])
|
27
|
-
|
28
27
|
docs = base.view(view_name, :key => value, :limit => 2, :include_docs => false)['rows']
|
29
28
|
return if docs.empty?
|
30
29
|
|
@@ -127,18 +127,11 @@ module CouchRest
|
|
127
127
|
if raw || (opts.has_key?(:include_docs) && opts[:include_docs] == false)
|
128
128
|
fetch_view(db, name, opts, &block)
|
129
129
|
else
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
view['rows'].collect{|r|create_from_database(r['doc'])} if view['rows']
|
136
|
-
end
|
137
|
-
rescue
|
138
|
-
# fallback for old versions of couchdb that don't
|
139
|
-
# have include_docs support
|
140
|
-
view = fetch_view(db, name, opts, &block)
|
141
|
-
view['rows'].collect{|r|create_from_database(db.get(r['id']))} if view['rows']
|
130
|
+
if block.nil?
|
131
|
+
collection_proxy_for(design_doc, name, opts.merge({:database => db, :include_docs => true}))
|
132
|
+
else
|
133
|
+
view = fetch_view db, name, opts.merge({:include_docs => true}), &block
|
134
|
+
view['rows'].collect{|r|create_from_database(r['doc'])} if view['rows']
|
142
135
|
end
|
143
136
|
end
|
144
137
|
end
|
data/lib/couchrest/model.rb
CHANGED
data/lib/couchrest_model.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
|
2
|
-
# require File.join(File.dirname(__FILE__), "couchrest", "extended_document")
|
3
|
-
|
4
|
-
gem 'couchrest'
|
5
|
-
|
1
|
+
gem 'couchrest', ">= 1.0.0.beta"
|
6
2
|
require 'couchrest'
|
7
3
|
|
4
|
+
gem "tzinfo", ">= 0.3.22"
|
5
|
+
|
6
|
+
gem "activesupport", ">= 2.3.5"
|
8
7
|
require 'active_support/core_ext'
|
9
8
|
require 'active_support/json'
|
9
|
+
|
10
|
+
gem "activemodel", ">= 3.0.0.beta4"
|
10
11
|
require 'active_model'
|
11
12
|
require "active_model/callbacks"
|
12
13
|
require "active_model/conversion"
|
@@ -17,6 +18,8 @@ require "active_model/serialization"
|
|
17
18
|
require "active_model/translation"
|
18
19
|
require "active_model/validator"
|
19
20
|
require "active_model/validations"
|
21
|
+
|
22
|
+
gem "mime-types", ">= 1.15"
|
20
23
|
require 'mime/types'
|
21
24
|
require "enumerator"
|
22
25
|
require "time"
|
@@ -54,3 +57,5 @@ require "couchrest/model/base"
|
|
54
57
|
|
55
58
|
# Add rails support *after* everything has loaded
|
56
59
|
|
60
|
+
require "couchrest/railtie"
|
61
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rails/generators/couchrest_model'
|
2
|
+
|
3
|
+
module CouchrestModel
|
4
|
+
module Generators
|
5
|
+
class ModelGenerator < Base
|
6
|
+
|
7
|
+
check_class_collision
|
8
|
+
|
9
|
+
def create_model_file
|
10
|
+
template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_module_file
|
14
|
+
return if class_path.empty?
|
15
|
+
template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def parent_class_name
|
21
|
+
"CouchRest::Model::Base"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
require 'rails/generators/active_model'
|
3
|
+
require 'couchrest_model'
|
4
|
+
|
5
|
+
module CouchrestModel
|
6
|
+
module Generators
|
7
|
+
class Base < Rails::Generators::NamedBase #:nodoc:
|
8
|
+
|
9
|
+
# Set the current directory as base for the inherited generators.
|
10
|
+
def self.base_root
|
11
|
+
File.dirname(__FILE__)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,31 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
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
|
3
|
+
require File.join(FIXTURE_PATH, 'more', 'sale_invoice')
|
29
4
|
|
30
5
|
|
31
6
|
describe "Assocations" do
|
@@ -33,7 +8,7 @@ describe "Assocations" do
|
|
33
8
|
describe "of type belongs to" do
|
34
9
|
|
35
10
|
before :each do
|
36
|
-
@invoice = SaleInvoice.create(:price =>
|
11
|
+
@invoice = SaleInvoice.create(:price => 2000)
|
37
12
|
@client = Client.create(:name => "Sam Lown")
|
38
13
|
end
|
39
14
|
|
@@ -94,7 +69,7 @@ describe "Assocations" do
|
|
94
69
|
describe "of type collection_of" do
|
95
70
|
|
96
71
|
before(:each) do
|
97
|
-
@invoice = SaleInvoice.create(:price =>
|
72
|
+
@invoice = SaleInvoice.create(:price => 2000)
|
98
73
|
@entries = [
|
99
74
|
SaleEntry.create(:description => 'test line 1', :price => 500),
|
100
75
|
SaleEntry.create(:description => 'test line 2', :price => 500),
|
@@ -121,7 +96,7 @@ describe "Assocations" do
|
|
121
96
|
@invoice.entries.length.should eql(3)
|
122
97
|
@invoice.entries.first.should eql(@entries.first)
|
123
98
|
end
|
124
|
-
|
99
|
+
|
125
100
|
it "should replace collection if ids replaced" do
|
126
101
|
@invoice.entry_ids = @entries.collect{|i| i.id}
|
127
102
|
@invoice.entries.length.should eql(3) # load once
|
@@ -135,7 +110,7 @@ describe "Assocations" do
|
|
135
110
|
@invoice.entry_ids << @entries[2].id
|
136
111
|
@invoice.entry_ids.length.should eql(3)
|
137
112
|
@invoice.entries.length.should eql(2) # cached!
|
138
|
-
@invoice.entries(true).length.should eql(3)
|
113
|
+
@invoice.entries(true).length.should eql(3)
|
139
114
|
end
|
140
115
|
|
141
116
|
it "should empty arrays when nil collection provided" do
|
@@ -203,11 +178,19 @@ describe "Assocations" do
|
|
203
178
|
@invoice.entry_ids.first.should eql(@entries[1].id)
|
204
179
|
end
|
205
180
|
|
181
|
+
it "should raise error when adding un-persisted entries" do
|
182
|
+
SaleEntry.find_by_description('test entry').should be_nil
|
183
|
+
entry = SaleEntry.new(:description => 'test entry', :price => 500)
|
184
|
+
lambda {
|
185
|
+
@invoice.entries << entry
|
186
|
+
}.should raise_error
|
187
|
+
# In the future maybe?
|
188
|
+
# @invoice.save.should be_true
|
189
|
+
# SaleEntry.find_by_description('test entry').should_not be_nil
|
190
|
+
end
|
206
191
|
|
207
192
|
end
|
208
|
-
|
209
193
|
|
210
194
|
end
|
211
195
|
|
212
196
|
end
|
213
|
-
|
@@ -30,6 +30,13 @@ describe "Model attachments" do
|
|
30
30
|
@obj.delete_attachment(@attachment_name)
|
31
31
|
@obj.has_attachment?(@attachment_name).should be_false
|
32
32
|
end
|
33
|
+
|
34
|
+
it 'should return false if an attachment has been removed and reloaded' do
|
35
|
+
@obj.delete_attachment(@attachment_name)
|
36
|
+
reloaded_obj = Basic.get(@obj.id)
|
37
|
+
reloaded_obj.has_attachment?(@attachment_name).should be_false
|
38
|
+
end
|
39
|
+
|
33
40
|
end
|
34
41
|
|
35
42
|
describe "creating an attachment" do
|
@@ -46,14 +53,14 @@ describe "Model attachments" do
|
|
46
53
|
@obj.create_attachment(:file => @file_ext, :name => @attachment_name)
|
47
54
|
@obj.save.should be_true
|
48
55
|
reloaded_obj = Basic.get(@obj.id)
|
49
|
-
reloaded_obj[
|
56
|
+
reloaded_obj.attachments[@attachment_name].should_not be_nil
|
50
57
|
end
|
51
58
|
|
52
59
|
it "should create an attachment from file without an extension" do
|
53
60
|
@obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
|
54
61
|
@obj.save.should be_true
|
55
62
|
reloaded_obj = Basic.get(@obj.id)
|
56
|
-
reloaded_obj[
|
63
|
+
reloaded_obj.attachments[@attachment_name].should_not be_nil
|
57
64
|
end
|
58
65
|
|
59
66
|
it 'should raise ArgumentError if :file is missing' do
|
@@ -66,19 +73,19 @@ describe "Model attachments" do
|
|
66
73
|
|
67
74
|
it 'should set the content-type if passed' do
|
68
75
|
@obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
|
69
|
-
@obj[
|
76
|
+
@obj.attachments[@attachment_name]['content_type'].should == @content_type
|
70
77
|
end
|
71
78
|
|
72
79
|
it "should detect the content-type automatically" do
|
73
80
|
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
74
|
-
@obj['
|
81
|
+
@obj.attachments['couchdb.png']['content_type'].should == "image/png"
|
75
82
|
end
|
76
83
|
|
77
84
|
it "should use name to detect the content-type automatically if no file" do
|
78
85
|
file = File.open(FIXTURE_PATH + '/attachments/couchdb.png')
|
79
86
|
file.stub!(:path).and_return("badfilname")
|
80
87
|
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
81
|
-
@obj['
|
88
|
+
@obj.attachments['couchdb.png']['content_type'].should == "image/png"
|
82
89
|
end
|
83
90
|
|
84
91
|
end
|
@@ -113,7 +120,7 @@ describe "Model attachments" do
|
|
113
120
|
file = File.open(FIXTURE_PATH + '/attachments/README')
|
114
121
|
@file.should_not == file
|
115
122
|
@obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
|
116
|
-
@obj[
|
123
|
+
@obj.attachments[@attachment_name]['content_type'].should == @content_type
|
117
124
|
end
|
118
125
|
|
119
126
|
it 'should delete an attachment that exists' do
|
@@ -143,6 +150,27 @@ describe "Model attachments" do
|
|
143
150
|
it 'should return the attachment URI' do
|
144
151
|
@obj.attachment_uri(@attachment_name).should == "#{Basic.database.uri}/#{@obj.id}/#{@attachment_name}"
|
145
152
|
end
|
146
|
-
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#attachments" do
|
156
|
+
before(:each) do
|
157
|
+
@obj = Basic.new
|
158
|
+
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
159
|
+
@attachment_name = 'my_attachment'
|
160
|
+
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
161
|
+
@obj.save.should be_true
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should return an empty Hash when document does not have any attachment' do
|
165
|
+
new_obj = Basic.new
|
166
|
+
new_obj.save.should be_true
|
167
|
+
new_obj.attachments.should == {}
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should return a Hash with all attachments' do
|
171
|
+
@file.rewind
|
172
|
+
@obj.attachments.should == { @attachment_name =>{ "data" => "PCFET0NUWVBFIGh0bWw+CjxodG1sPgogIDxoZWFkPgogICAgPHRpdGxlPlRlc3Q8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgIDxwPgogICAgICBUZXN0CiAgICA8L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==", "content_type" => "text/html"}}
|
173
|
+
end
|
174
|
+
|
147
175
|
end
|
148
176
|
end
|