langalex-couch_potato 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CREDITS +3 -0
- data/MIT-LICENSE.txt +19 -0
- data/init.rb +5 -0
- data/lib/core_ext/object.rb +5 -0
- data/lib/core_ext/time.rb +14 -0
- data/lib/couch_potato/active_record/compatibility.rb +9 -0
- data/lib/couch_potato/ordering.rb +88 -0
- data/lib/couch_potato/persistence/belongs_to_property.rb +44 -0
- data/lib/couch_potato/persistence/bulk_save_queue.rb +47 -0
- data/lib/couch_potato/persistence/callbacks.rb +96 -0
- data/lib/couch_potato/persistence/collection.rb +51 -0
- data/lib/couch_potato/persistence/external_collection.rb +54 -0
- data/lib/couch_potato/persistence/external_has_many_property.rb +68 -0
- data/lib/couch_potato/persistence/find.rb +21 -0
- data/lib/couch_potato/persistence/finder.rb +109 -0
- data/lib/couch_potato/persistence/inline_collection.rb +14 -0
- data/lib/couch_potato/persistence/inline_has_many_property.rb +39 -0
- data/lib/couch_potato/persistence/json.rb +46 -0
- data/lib/couch_potato/persistence/properties.rb +40 -0
- data/lib/couch_potato/persistence/simple_property.rb +33 -0
- data/lib/couch_potato/persistence.rb +186 -0
- data/lib/couch_potato/versioning.rb +46 -0
- data/lib/couch_potato.rb +20 -0
- data/spec/attributes_spec.rb +22 -0
- data/spec/belongs_to_spec.rb +37 -0
- data/spec/callbacks_spec.rb +229 -0
- data/spec/create_spec.rb +68 -0
- data/spec/destroy_spec.rb +24 -0
- data/spec/find_spec.rb +88 -0
- data/spec/finder_spec.rb +115 -0
- data/spec/has_many_spec.rb +178 -0
- data/spec/inline_collection_spec.rb +15 -0
- data/spec/ordering_spec.rb +94 -0
- data/spec/property_spec.rb +46 -0
- data/spec/reload_spec.rb +46 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/update_spec.rb +33 -0
- data/spec/versioning_spec.rb +149 -0
- metadata +132 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
class InlineHasManyProperty
|
2
|
+
attr_accessor :name
|
3
|
+
|
4
|
+
def initialize(owner_clazz, name, options = {})
|
5
|
+
@name = name
|
6
|
+
getter = <<-GETTER
|
7
|
+
def #{name}
|
8
|
+
@#{name} ||= CouchPotato::Persistence::InlineCollection.new(#{item_class_name})
|
9
|
+
end
|
10
|
+
GETTER
|
11
|
+
owner_clazz.class_eval getter
|
12
|
+
end
|
13
|
+
|
14
|
+
def build(object, json)
|
15
|
+
object.send("#{name}").clear
|
16
|
+
json[name.to_s].each do |item|
|
17
|
+
item.delete 'ruby_class'
|
18
|
+
object.send("#{name}").build item
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def save(object)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize(json, object)
|
27
|
+
json[name.to_s] = object.send(name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy(object)
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def item_class_name
|
37
|
+
@name.to_s.singularize.camelcase
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
module Persistence
|
3
|
+
module Json
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_json(*args)
|
9
|
+
(self.class.properties).inject({}) do |props, property|
|
10
|
+
property.serialize(props, self)
|
11
|
+
props
|
12
|
+
end.merge('ruby_class' => self.class.name).merge(id_and_rev_json).merge(timestamps_json).to_json(*args)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def id_and_rev_json
|
18
|
+
[:_id, :_rev, :_deleted].inject({}) do |hash, key|
|
19
|
+
hash[key] = self.send(key) unless self.send(key).nil?
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def timestamps_json
|
25
|
+
[:created_at, :updated_at].inject({}) do |hash, key|
|
26
|
+
hash[key] = self.send(key).to_s unless self.send(key).nil?
|
27
|
+
hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
def json_create(json)
|
33
|
+
instance = self.new
|
34
|
+
instance.created_at = Time.parse(json['created_at'])
|
35
|
+
instance.updated_at = Time.parse(json['updated_at'])
|
36
|
+
instance._id = json['_id']
|
37
|
+
instance._rev = json['_rev']
|
38
|
+
properties.each do |property|
|
39
|
+
property.build(instance, json)
|
40
|
+
end
|
41
|
+
instance
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/simple_property'
|
2
|
+
require File.dirname(__FILE__) + '/belongs_to_property'
|
3
|
+
require File.dirname(__FILE__) + '/inline_has_many_property'
|
4
|
+
require File.dirname(__FILE__) + '/external_has_many_property'
|
5
|
+
|
6
|
+
module CouchPotato
|
7
|
+
module Persistence
|
8
|
+
module Properties
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
base.class_eval do
|
12
|
+
def self.properties
|
13
|
+
@@properties ||= {}
|
14
|
+
@@properties[self.name] ||= []
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def property_names
|
21
|
+
properties.map(&:name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def property(name, options = {})
|
25
|
+
clazz = options.delete(:class)
|
26
|
+
properties << (clazz || SimpleProperty).new(self, name, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def belongs_to(name)
|
30
|
+
property name, :class => BelongsToProperty
|
31
|
+
end
|
32
|
+
|
33
|
+
def has_many(name, options = {})
|
34
|
+
stored = options.delete(:stored)
|
35
|
+
property name, options.merge(:class => (stored == :inline ? InlineHasManyProperty : ExternalHasManyProperty))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
module Persistence
|
3
|
+
class SimpleProperty
|
4
|
+
attr_accessor :name
|
5
|
+
|
6
|
+
def initialize(owner_clazz, name, options = {})
|
7
|
+
self.name = name
|
8
|
+
owner_clazz.class_eval do
|
9
|
+
attr_accessor name
|
10
|
+
define_method "#{name}?" do
|
11
|
+
!self.send(name).nil? && !self.send(name).try(:blank?)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def build(object, json)
|
17
|
+
object.send "#{name}=", json.stringify_keys[name.to_s]
|
18
|
+
end
|
19
|
+
|
20
|
+
def save(object)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy(object)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialize(json, object)
|
29
|
+
json[name] = object.send name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'couchrest'
|
3
|
+
require 'validatable'
|
4
|
+
require File.dirname(__FILE__) + '/persistence/inline_collection'
|
5
|
+
require File.dirname(__FILE__) + '/persistence/external_collection'
|
6
|
+
require File.dirname(__FILE__) + '/persistence/properties'
|
7
|
+
require File.dirname(__FILE__) + '/persistence/callbacks'
|
8
|
+
require File.dirname(__FILE__) + '/persistence/json'
|
9
|
+
require File.dirname(__FILE__) + '/persistence/bulk_save_queue'
|
10
|
+
require File.dirname(__FILE__) + '/persistence/find'
|
11
|
+
|
12
|
+
module CouchPotato
|
13
|
+
module Persistence
|
14
|
+
|
15
|
+
class ValidationsFailedError < ::Exception; end
|
16
|
+
class UnsavedRecordError < ::Exception; end
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.send :extend, ClassMethods, Find
|
20
|
+
base.send :include, Callbacks, Properties, Validatable, Json
|
21
|
+
base.class_eval do
|
22
|
+
attr_accessor :_id, :_rev, :_attachments, :_deleted, :created_at, :updated_at
|
23
|
+
attr_reader :bulk_save_queue
|
24
|
+
alias_method :id, :_id
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(attributes = {})
|
29
|
+
@bulk_save_queue = BulkSaveQueue.new
|
30
|
+
attributes.each do |name, value|
|
31
|
+
self.send("#{name}=", value)
|
32
|
+
end if attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
def attributes=(hash)
|
36
|
+
hash.each do |attribute, value|
|
37
|
+
self.send "#{attribute}=", value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def attributes
|
42
|
+
self.class.properties.inject({}) do |res, property|
|
43
|
+
property.serialize(res, self)
|
44
|
+
res
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def save!
|
49
|
+
save || raise(ValidationsFailedError.new(self.errors.full_messages))
|
50
|
+
end
|
51
|
+
|
52
|
+
def save
|
53
|
+
if new_document?
|
54
|
+
create_document
|
55
|
+
else
|
56
|
+
update_document
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def destroy
|
61
|
+
run_callbacks(:before_destroy)
|
62
|
+
self._deleted = true
|
63
|
+
bulk_save_queue << self
|
64
|
+
destroy_dependent_objects
|
65
|
+
bulk_save_queue.save do |res|
|
66
|
+
self._id = nil
|
67
|
+
self._rev = nil
|
68
|
+
end
|
69
|
+
run_callbacks(:after_destroy)
|
70
|
+
end
|
71
|
+
|
72
|
+
def reload
|
73
|
+
raise(UnsavedRecordError.new) unless _id
|
74
|
+
json = self.class.db.get _id
|
75
|
+
self.class.properties.each do |property|
|
76
|
+
property.build self, json
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def new_document?
|
81
|
+
_id.nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_param
|
85
|
+
_id
|
86
|
+
end
|
87
|
+
|
88
|
+
def [](name)
|
89
|
+
self.send name
|
90
|
+
end
|
91
|
+
|
92
|
+
def ==(other)
|
93
|
+
other.class == self.class && self.class.property_names.map{|name| self.send(name)} == self.class.property_names.map{|name| other.send(name)}
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def create_document
|
99
|
+
run_callbacks :before_validation_on_save
|
100
|
+
run_callbacks :before_validation_on_create
|
101
|
+
return unless valid?
|
102
|
+
run_callbacks :before_save
|
103
|
+
run_callbacks :before_create
|
104
|
+
self.created_at = Time.now
|
105
|
+
self.updated_at = Time.now
|
106
|
+
self._id = self.class.db.server.next_uuid rescue Digest::MD5.hexdigest(rand(1000000000000).to_s) # only works with couchdb 0.9
|
107
|
+
bulk_save_queue << self
|
108
|
+
save_dependent_objects
|
109
|
+
bulk_save_queue.save do |res|
|
110
|
+
self._rev = extract_rev(res)
|
111
|
+
end
|
112
|
+
run_callbacks :after_save
|
113
|
+
run_callbacks :after_create
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
def extract_rev(res)
|
118
|
+
res['new_revs'].select{|hash| hash['id'] == self.id}.first['rev']
|
119
|
+
end
|
120
|
+
|
121
|
+
def update_document
|
122
|
+
run_callbacks(:before_validation_on_save)
|
123
|
+
run_callbacks(:before_validation_on_update)
|
124
|
+
return unless valid?
|
125
|
+
run_callbacks :before_save
|
126
|
+
run_callbacks :before_update
|
127
|
+
self.updated_at = Time.now
|
128
|
+
bulk_save_queue << self
|
129
|
+
save_dependent_objects
|
130
|
+
bulk_save_queue.save do |res|
|
131
|
+
self._rev = extract_rev(res)
|
132
|
+
end
|
133
|
+
run_callbacks :after_save
|
134
|
+
run_callbacks :after_update
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
def save_dependent_objects
|
139
|
+
self.class.properties.each do |property|
|
140
|
+
property.save(self)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def destroy_dependent_objects
|
145
|
+
self.class.properties.each do |property|
|
146
|
+
property.destroy(self)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
module ClassMethods
|
151
|
+
|
152
|
+
def create!(attributes = {})
|
153
|
+
instance = self.new attributes
|
154
|
+
instance.save!
|
155
|
+
instance
|
156
|
+
end
|
157
|
+
|
158
|
+
def create(attributes = {})
|
159
|
+
instance = self.new attributes
|
160
|
+
instance.save
|
161
|
+
instance
|
162
|
+
end
|
163
|
+
|
164
|
+
def get(id)
|
165
|
+
begin
|
166
|
+
self.json_create db.get(id)
|
167
|
+
rescue(RestClient::ResourceNotFound)
|
168
|
+
nil
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def db(name = nil)
|
173
|
+
::CouchPotato::Persistence.Db(name)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.Db(database_name = nil)
|
178
|
+
database_name ||= CouchPotato::Config.database_name || raise('No Database configured. Set CouchPotato::Config.database_name')
|
179
|
+
full_url_to_database = database_name
|
180
|
+
if full_url_to_database !~ /^http:\/\//
|
181
|
+
full_url_to_database = "http://localhost:5984/#{database_name}"
|
182
|
+
end
|
183
|
+
CouchRest.database!(full_url_to_database)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
module Versioning
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
property :version
|
6
|
+
property :master_version_id
|
7
|
+
cattr_accessor :new_version_condition
|
8
|
+
before_create :set_version_default
|
9
|
+
before_update :prepare_for_new_version
|
10
|
+
|
11
|
+
def self.set_version_condition(lambda)
|
12
|
+
self.new_version_condition = lambda
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def versions(version_no = nil)
|
18
|
+
if version_no
|
19
|
+
CouchPotato::Persistence::Finder.new.find(self.class, :version => version_no).first
|
20
|
+
elsif version == 1
|
21
|
+
[self]
|
22
|
+
else
|
23
|
+
CouchPotato::Persistence::Finder.new.find(self.class, :master_version_id => _id).sort_by(&:version)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def set_version_default
|
30
|
+
self.version ||= 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def prepare_for_new_version
|
34
|
+
if new_version_condition.nil? || new_version_condition.call(self)
|
35
|
+
copy = self.class.get self._id
|
36
|
+
copy._id = nil
|
37
|
+
copy._rev = nil
|
38
|
+
copy.master_version_id = self._id
|
39
|
+
copy.save
|
40
|
+
self.master_version_id ||= self.id
|
41
|
+
self.version += 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/lib/couch_potato.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'json'
|
4
|
+
require 'json/add/core'
|
5
|
+
require 'json/add/rails'
|
6
|
+
|
7
|
+
require 'ostruct'
|
8
|
+
|
9
|
+
module CouchPotato
|
10
|
+
Config = OpenStruct.new
|
11
|
+
end
|
12
|
+
|
13
|
+
require File.dirname(__FILE__) + '/core_ext/object'
|
14
|
+
require File.dirname(__FILE__) + '/core_ext/time'
|
15
|
+
|
16
|
+
require File.dirname(__FILE__) + '/couch_potato/persistence'
|
17
|
+
require File.dirname(__FILE__) + '/couch_potato/versioning'
|
18
|
+
require File.dirname(__FILE__) + '/couch_potato/ordering'
|
19
|
+
require File.dirname(__FILE__) + '/couch_potato/active_record/compatibility'
|
20
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe 'attributes=' do
|
4
|
+
|
5
|
+
class Plant
|
6
|
+
include CouchPotato::Persistence
|
7
|
+
property :leaf_count
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should assign the attributes" do
|
11
|
+
plant = Plant.new
|
12
|
+
plant.attributes = {:leaf_count => 1}
|
13
|
+
plant.leaf_count.should == 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "attributes" do
|
18
|
+
it "should return the attributes" do
|
19
|
+
plant = Plant.new :leaf_count => 1
|
20
|
+
plant.attributes .should == {:leaf_count => 1}
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe 'belongs_to' do
|
4
|
+
before(:each) do
|
5
|
+
@commenter = Commenter.create!
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return nil by default" do
|
9
|
+
c = Comment.new :title => 'title'
|
10
|
+
c.commenter.should be_nil
|
11
|
+
c.commenter_id.should be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should assign the parent object" do
|
15
|
+
c = Comment.new :title => 'title'
|
16
|
+
c.commenter = @commenter
|
17
|
+
c.commenter.should == @commenter
|
18
|
+
c.commenter_id.should == @commenter.id
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should assign the parent object id" do
|
22
|
+
c = Comment.new :title => 'title'
|
23
|
+
c.commenter_id = @commenter.id
|
24
|
+
c.commenter.should == @commenter
|
25
|
+
c.commenter_id.should == @commenter.id
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should persist the link to the parent object" do
|
29
|
+
c = Comment.new :title => 'title'
|
30
|
+
c.commenter_id = @commenter.id
|
31
|
+
c.save!
|
32
|
+
c = Comment.find c.id
|
33
|
+
c.commenter._id.should == @commenter.id
|
34
|
+
c.commenter_id.should == @commenter._id
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class CallbackRecorder
|
4
|
+
include CouchPotato::Persistence
|
5
|
+
|
6
|
+
property :required_property
|
7
|
+
|
8
|
+
validates_presence_of :required_property
|
9
|
+
|
10
|
+
[:before_validation_on_create,
|
11
|
+
:before_validation_on_save, :before_validation_on_update,
|
12
|
+
:before_save, :before_create, :before_create,
|
13
|
+
:after_save, :after_create, :after_create,
|
14
|
+
:before_update, :after_update,
|
15
|
+
:before_destroy, :after_destroy
|
16
|
+
].each do |callback|
|
17
|
+
define_method callback do
|
18
|
+
callbacks << callback
|
19
|
+
end
|
20
|
+
self.send callback, callback
|
21
|
+
end
|
22
|
+
|
23
|
+
def callbacks
|
24
|
+
@callbacks ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "multiple callbacks at once" do
|
30
|
+
class Monkey
|
31
|
+
include CouchPotato::Persistence
|
32
|
+
attr_accessor :eaten_banana, :eaten_apple
|
33
|
+
|
34
|
+
before_create :eat_apple, :eat_banana
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def eat_banana
|
39
|
+
self.eaten_banana = true
|
40
|
+
end
|
41
|
+
|
42
|
+
def eat_apple
|
43
|
+
self.eaten_apple = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
it "should run all callback methods given to the callback method call" do
|
47
|
+
monkey = Monkey.create!
|
48
|
+
monkey.eaten_banana.should be_true
|
49
|
+
monkey.eaten_apple.should be_true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'create callbacks' do
|
54
|
+
|
55
|
+
before(:each) do
|
56
|
+
@recorder = CallbackRecorder.new
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "successful create" do
|
60
|
+
before(:each) do
|
61
|
+
@recorder.required_property = 1
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should call before_validation_on_create" do
|
65
|
+
@recorder.save!
|
66
|
+
@recorder.callbacks.should include(:before_validation_on_create)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should call before_validation_on_save" do
|
70
|
+
@recorder.save!
|
71
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should call before_save" do
|
75
|
+
@recorder.save!
|
76
|
+
@recorder.callbacks.should include(:before_save)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should call after_save" do
|
80
|
+
@recorder.save!
|
81
|
+
@recorder.callbacks.should include(:after_save)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should call before_create" do
|
85
|
+
@recorder.save!
|
86
|
+
@recorder.callbacks.should include(:before_create)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should call after_create" do
|
90
|
+
@recorder.save!
|
91
|
+
@recorder.callbacks.should include(:after_create)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "failed create" do
|
97
|
+
|
98
|
+
it "should call before_validation_on_create" do
|
99
|
+
@recorder.save
|
100
|
+
@recorder.callbacks.should include(:before_validation_on_create)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should call before_validation_on_save" do
|
104
|
+
@recorder.save
|
105
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should not call before_save" do
|
109
|
+
@recorder.save
|
110
|
+
@recorder.callbacks.should_not include(:before_save)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not call after_save" do
|
114
|
+
@recorder.save
|
115
|
+
@recorder.callbacks.should_not include(:after_save)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not call before_create" do
|
119
|
+
@recorder.save
|
120
|
+
@recorder.callbacks.should_not include(:before_create)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should not call after_create" do
|
124
|
+
@recorder.save
|
125
|
+
@recorder.callbacks.should_not include(:after_create)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "update callbacks" do
|
134
|
+
|
135
|
+
before(:each) do
|
136
|
+
@recorder = CallbackRecorder.create! :required_property => 1
|
137
|
+
@recorder.callbacks.clear
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "successful update" do
|
141
|
+
|
142
|
+
it "should call before_validation_on_update" do
|
143
|
+
@recorder.save!
|
144
|
+
@recorder.callbacks.should include(:before_validation_on_update)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should call before_validation_on_save" do
|
148
|
+
@recorder.save!
|
149
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should call before_save" do
|
153
|
+
@recorder.save!
|
154
|
+
@recorder.callbacks.should include(:before_save)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should call after_save" do
|
158
|
+
@recorder.save!
|
159
|
+
@recorder.callbacks.should include(:after_save)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should call before_update" do
|
163
|
+
@recorder.save!
|
164
|
+
@recorder.callbacks.should include(:before_update)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should call after_update" do
|
168
|
+
@recorder.save!
|
169
|
+
@recorder.callbacks.should include(:after_update)
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "failed update" do
|
175
|
+
|
176
|
+
before(:each) do
|
177
|
+
@recorder.required_property = nil
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should call before_validation_on_update" do
|
181
|
+
@recorder.save
|
182
|
+
@recorder.callbacks.should include(:before_validation_on_update)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should call before_validation_on_save" do
|
186
|
+
@recorder.save
|
187
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should not call before_save" do
|
191
|
+
@recorder.save
|
192
|
+
@recorder.callbacks.should_not include(:before_save)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should not call after_save" do
|
196
|
+
@recorder.save
|
197
|
+
@recorder.callbacks.should_not include(:after_save)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should not call before_update" do
|
201
|
+
@recorder.save
|
202
|
+
@recorder.callbacks.should_not include(:before_update)
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should not call after_update" do
|
206
|
+
@recorder.save
|
207
|
+
@recorder.callbacks.should_not include(:after_update)
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "destroy callbacks" do
|
215
|
+
before(:each) do
|
216
|
+
@recorder = CallbackRecorder.create! :required_property => 1
|
217
|
+
@recorder.callbacks.clear
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should call before_destroy" do
|
221
|
+
@recorder.destroy
|
222
|
+
@recorder.callbacks.should include(:before_destroy)
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should call after_destroy" do
|
226
|
+
@recorder.destroy
|
227
|
+
@recorder.callbacks.should include(:after_destroy)
|
228
|
+
end
|
229
|
+
end
|