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