requires_approval_rails_2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,90 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "requires_approval_rails_2"
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dan Langevin"]
12
+ s.date = "2012-08-05"
13
+ s.description = "Gem to handle versioning and things that require approval"
14
+ s.email = "dan.langevin@lifebooker.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "Guardfile",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "lib/errors.rb",
30
+ "lib/requires_approval.rb",
31
+ "requires_approval_rails_2.gemspec",
32
+ "spec/lib/requires_approval_spec.rb",
33
+ "spec/spec_helper.rb",
34
+ "spec/support/BLANK"
35
+ ]
36
+ s.homepage = "http://github.com/LifebookerInc/requires_approval"
37
+ s.licenses = ["MIT"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = "1.8.11"
40
+ s.summary = "Gem to handle versioning and things that require approval"
41
+
42
+ if s.respond_to? :specification_version then
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<activerecord>, ["~> 2.3"])
47
+ s.add_runtime_dependency(%q<activesupport>, ["~> 2.3"])
48
+ s.add_development_dependency(%q<bundler>, [">= 0"])
49
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
50
+ s.add_development_dependency(%q<guard-bundler>, [">= 0"])
51
+ s.add_development_dependency(%q<guard-spork>, [">= 0"])
52
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
53
+ s.add_development_dependency(%q<mocha>, [">= 0"])
54
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
55
+ s.add_development_dependency(%q<rspec>, [">= 0"])
56
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
57
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
58
+ s.add_development_dependency(%q<yard>, [">= 0"])
59
+ else
60
+ s.add_dependency(%q<activerecord>, ["~> 2.3"])
61
+ s.add_dependency(%q<activesupport>, ["~> 2.3"])
62
+ s.add_dependency(%q<bundler>, [">= 0"])
63
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
64
+ s.add_dependency(%q<guard-bundler>, [">= 0"])
65
+ s.add_dependency(%q<guard-spork>, [">= 0"])
66
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
67
+ s.add_dependency(%q<mocha>, [">= 0"])
68
+ s.add_dependency(%q<rdoc>, [">= 0"])
69
+ s.add_dependency(%q<rspec>, [">= 0"])
70
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
71
+ s.add_dependency(%q<sqlite3>, [">= 0"])
72
+ s.add_dependency(%q<yard>, [">= 0"])
73
+ end
74
+ else
75
+ s.add_dependency(%q<activerecord>, ["~> 2.3"])
76
+ s.add_dependency(%q<activesupport>, ["~> 2.3"])
77
+ s.add_dependency(%q<bundler>, [">= 0"])
78
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
79
+ s.add_dependency(%q<guard-bundler>, [">= 0"])
80
+ s.add_dependency(%q<guard-spork>, [">= 0"])
81
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
82
+ s.add_dependency(%q<mocha>, [">= 0"])
83
+ s.add_dependency(%q<rdoc>, [">= 0"])
84
+ s.add_dependency(%q<rspec>, [">= 0"])
85
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
86
+ s.add_dependency(%q<sqlite3>, [">= 0"])
87
+ s.add_dependency(%q<yard>, [">= 0"])
88
+ end
89
+ end
90
+
@@ -0,0 +1,423 @@
1
+ require 'spec_helper'
2
+
3
+ describe RequiresApproval do
4
+
5
+ before(:all) do
6
+
7
+ ActiveRecord::Base.establish_connection({
8
+ "adapter" => "sqlite3",
9
+ "database" => File.join(File.dirname(__FILE__), "..", "support", "db.sqlite")
10
+ })
11
+
12
+ ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
13
+ t.string(:first_name)
14
+ t.string(:last_name)
15
+ t.date(:birthday)
16
+ t.timestamps
17
+ end
18
+
19
+ class User < ActiveRecord::Base
20
+ requires_approval_for(:first_name, :last_name)
21
+ end
22
+
23
+ User.prepare_tables_for_requires_approval
24
+
25
+ end
26
+
27
+
28
+ context "setup" do
29
+
30
+ context "database" do
31
+
32
+ it "should create a versions table" do
33
+ User.connection.tables.should include "user_versions"
34
+ end
35
+
36
+ it "should add an is_active column to the parent table" do
37
+ User.column_names.should include "is_frozen"
38
+ col = User.columns.select{|c| c.name == "is_frozen"}.first
39
+ col.type.should be :boolean
40
+ col.default.should be true
41
+ end
42
+
43
+ it "should add an is_deleted column to the parent table" do
44
+ User.column_names.should include "is_deleted"
45
+ col = User.columns.select{|c| c.name == "is_deleted"}.first
46
+ col.type.should be :boolean
47
+ col.default.should be false
48
+ end
49
+
50
+ end
51
+
52
+ context "version class" do
53
+
54
+ it "should create an ActiveRecord class for its versions" do
55
+ defined?(User::Version).should eql "constant"
56
+ User::Version.table_name.should eql("user_versions")
57
+ end
58
+
59
+ it "should provide a getter for its versions class" do
60
+ User.versions_class.should be User::Version
61
+ end
62
+
63
+ end
64
+
65
+ context "options" do
66
+
67
+ before(:all) do
68
+ conn = ActiveRecord::Base.connection
69
+
70
+ conn.create_table(:posts, :force => true) do |t|
71
+ t.string(:title)
72
+ t.string(:body)
73
+ t.date(:published_at)
74
+ t.timestamps
75
+ end
76
+
77
+ class Post < ActiveRecord::Base
78
+ requires_approval_for(:title, :body, {
79
+ :versions_table_name => "blah_blah",
80
+ :versions_foreign_key => "test_id",
81
+ :versions_class_name => "SuperVersion"
82
+ })
83
+ end
84
+ Post.prepare_tables_for_requires_approval
85
+
86
+ end
87
+
88
+ it "should create a custom-named subclass" do
89
+ defined?(Post::SuperVersion).should_not be_nil
90
+ end
91
+
92
+ it "should allow for custom table names" do
93
+ Post::SuperVersion.table_name.should eql("blah_blah")
94
+ end
95
+
96
+ it "should allow for a custom foreign key" do
97
+ assn = Post.reflect_on_association(:versions)
98
+ assn.options[:foreign_key].should eql("test_id")
99
+
100
+ assn = Post.reflect_on_association(:latest_unapproved_version)
101
+ assn.options[:foreign_key].should eql("test_id")
102
+
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+
109
+ context "scopes" do
110
+
111
+ before(:each) do
112
+ User.delete_all
113
+ end
114
+
115
+ it "should add an unapproved scope that finds records
116
+ that have pending changes" do
117
+
118
+ user = User.create!(
119
+ :first_name => "Dan",
120
+ :last_name => "Langevin",
121
+ :birthday => Date.today
122
+ )
123
+ # has unapproved changes
124
+ User.unapproved.should include user
125
+
126
+ # approve them and it should not match the scope
127
+ user.approve_all_attributes
128
+ User.unapproved.should_not include user
129
+
130
+ end
131
+
132
+ end
133
+
134
+ context "saving" do
135
+
136
+ it "should create a new version as blank with is_frozen true, is_deleted
137
+ false, and the requires approval attributes saved in the versions
138
+ table" do
139
+ user = User.create(
140
+ :first_name => "Dan",
141
+ :last_name => "Langevin",
142
+ :birthday => Date.today
143
+ )
144
+ user.is_frozen.should be true
145
+ user.is_deleted.should be false
146
+ user.versions.length.should eql 1
147
+
148
+ # requires_approval attributes should not be set on the parent record
149
+ user.first_name.should be nil
150
+ user.last_name.should be nil
151
+
152
+ # regular attributes should be set
153
+ user.birthday.should_not be nil
154
+
155
+ # requires_approval attributes should be set on the version record
156
+ user.versions.last.first_name.should eql "Dan"
157
+ user.versions.last.last_name.should eql "Langevin"
158
+
159
+ end
160
+
161
+ it "should update the latest_unapproved_version
162
+ when a field that requires approval has changed" do
163
+
164
+ user = User.create(
165
+ :first_name => "Dan",
166
+ :last_name => "Langevin"
167
+ )
168
+ version = user.latest_unapproved_version
169
+ version.first_name.should eql("Dan")
170
+ version.last_name.should eql("Langevin")
171
+
172
+ user.update_attribute(:first_name, "Blah")
173
+
174
+ version = user.latest_unapproved_version(true)
175
+ version.reload.first_name.should eql("Blah")
176
+ end
177
+
178
+ it "should initialize a new latest_unapproved_version with
179
+ the attributes of the previously approved version" do
180
+
181
+ user = User.create(
182
+ :first_name => "Dan",
183
+ :last_name => "Langevin"
184
+ )
185
+ user.approve_all_attributes
186
+
187
+ user.first_name = "Other"
188
+ user.save
189
+
190
+ user.reload
191
+
192
+ user.latest_unapproved_version.last_name.should eql("Langevin")
193
+ user.approve_all_attributes
194
+
195
+ user.first_name.should eql("Other")
196
+ user.last_name.should eql("Langevin")
197
+
198
+ end
199
+
200
+ end
201
+
202
+ context ".validates_approved_field" do
203
+
204
+ it "should delegate to the requires_approval field" do
205
+ User.class_eval do
206
+ validates_approved_field :first_name,
207
+ :presence => true
208
+ end
209
+
210
+ user = User.new
211
+ user.should_not be_valid
212
+ errors = user.errors[:"latest_unapproved_version.first_name"]
213
+ errors.should include "can't be blank"
214
+
215
+ end
216
+
217
+ end
218
+
219
+ context "#approve_all_attributes" do
220
+
221
+ it "should flag the latest_unapproved_version as approved, set is_frozen
222
+ to false and update all attributes" do
223
+
224
+ user = User.create(
225
+ :first_name => "Dan",
226
+ :last_name => "Langevin"
227
+ )
228
+ user.approve_all_attributes
229
+
230
+ user.first_name.should eql("Dan")
231
+ user.last_name.should eql("Langevin")
232
+ user.is_frozen.should be false
233
+
234
+ user.latest_unapproved_version.should be nil
235
+ end
236
+
237
+ end
238
+
239
+ context "#approve_attributes" do
240
+
241
+ it "should flag the selected values as approved and create a
242
+ new latest_unapproved_version to hold changes that were not
243
+ approved" do
244
+
245
+ user = User.create(
246
+ :first_name => "Dan",
247
+ :last_name => "Langevin"
248
+ )
249
+ user.approve_all_attributes
250
+
251
+ user.update_attributes(
252
+ :first_name => "New First",
253
+ :last_name => "New Last"
254
+ )
255
+
256
+ user.approve_attributes(:first_name)
257
+
258
+ user.first_name.should eql("New First")
259
+ # last name was not approved, should still be nil
260
+ user.last_name.should eql "Langevin"
261
+ user.is_frozen.should be false
262
+
263
+ user.pending_changes.should eql({
264
+ "last_name" => {"was" => "Langevin", "became" => "New Last"}
265
+ })
266
+
267
+ # should create an approved version
268
+ user.versions.where(:is_approved => true).count.should be > 0
269
+
270
+ end
271
+
272
+ it "should throw an error if you try to approve fields that do not require approval
273
+ or do not exist" do
274
+
275
+ user = User.create(
276
+ :first_name => "Dan",
277
+ :last_name => "Langevin",
278
+ :birthday => Date.today
279
+ )
280
+ user.approve_attributes(:first_name, :last_name)
281
+ user.update_attributes({
282
+ :first_name => "New Name",
283
+ :last_name => "New Last Name"
284
+ })
285
+
286
+ # doesn't exist
287
+ lambda{user.approve_attributes(:x)}.should raise_error(RequiresApproval::InvalidFieldsError)
288
+ # doesn't require approval
289
+ lambda{user.approve_attributes(:birthday)}.should raise_error(RequiresApproval::InvalidFieldsError)
290
+
291
+ end
292
+
293
+ it "should throw an error if you try to approve only some of the fields that require approval
294
+ in a newly created object" do
295
+
296
+ user = User.create(
297
+ :first_name => "Dan",
298
+ :last_name => "Langevin",
299
+ :birthday => Date.today
300
+ )
301
+ lambda{user.approve_attributes(:first_name)}.should raise_error(
302
+ RequiresApproval::PartialApprovalForNewObject
303
+ )
304
+
305
+ end
306
+
307
+ end
308
+
309
+ context "#deny_attributes" do
310
+
311
+ it "should remove the denied attributes from the
312
+ pending_changes hash" do
313
+
314
+ user = User.create(
315
+ :first_name => "Dan",
316
+ :last_name => "Langevin"
317
+ )
318
+ user.approve_all_attributes
319
+
320
+ user.update_attributes(
321
+ :first_name => "Test",
322
+ :last_name => "User"
323
+ )
324
+
325
+ user.deny_attributes(:first_name)
326
+ user.first_name.should eql("Dan")
327
+ user.pending_changes.should eql({
328
+ "last_name" => {"was" => "Langevin", "became" => "User"}
329
+ })
330
+
331
+
332
+ end
333
+
334
+ it "should remove the unapproved version all together when all
335
+ attributes are denied" do
336
+
337
+ user = User.create(
338
+ :first_name => "Dan",
339
+ :last_name => "Langevin"
340
+ )
341
+ user.approve_all_attributes
342
+
343
+ user.update_attributes(
344
+ :first_name => "ABC",
345
+ :last_name => "DEFG"
346
+ )
347
+ user.deny_attributes(:first_name, :last_name)
348
+ user.latest_unapproved_version.should be nil
349
+
350
+ end
351
+
352
+ it "should throw an error if you try to deny
353
+ fields that do not require approval or do not exist" do
354
+
355
+ u = User.create(
356
+ :first_name => "Dan",
357
+ :last_name => "Langevin",
358
+ :birthday => Date.today
359
+ )
360
+ u.approve_all_attributes
361
+
362
+ u.update_attributes(:first_name => "A", :last_name => "B")
363
+
364
+ # doesn't exist
365
+ lambda{u.deny_attributes(:x)}.should raise_error(RequiresApproval::InvalidFieldsError)
366
+ # doesn't require approval
367
+ lambda{u.deny_attributes(:birthday)}.should raise_error(RequiresApproval::InvalidFieldsError)
368
+
369
+ end
370
+
371
+ it "should throw an error if you try to deny fields on a never-approved object" do
372
+
373
+ u = User.create(
374
+ :first_name => "Dan",
375
+ :last_name => "Langevin",
376
+ :birthday => Date.today
377
+ )
378
+
379
+ lambda{u.deny_attributes(:first_name, :last_name)}.should raise_error(
380
+ RequiresApproval::DenyingNeverApprovedError
381
+ )
382
+ end
383
+
384
+ end
385
+
386
+ context "#has_approved_version?" do
387
+
388
+ it "should return true if a version has ever been approved" do
389
+ user = User.create(:first_name => "Dan", :last_name => "Langevin")
390
+ user.approve_all_attributes
391
+ user.has_approved_version?.should be true
392
+ end
393
+
394
+ it "should return false if no version has ever been approved" do
395
+ user = User.create(:first_name => "Dan", :last_name => "Langevin")
396
+ user.has_approved_version?.should be false
397
+ end
398
+
399
+ end
400
+
401
+ context "#has_pending_changes?" do
402
+
403
+ let(:user) do
404
+ User.new
405
+ end
406
+
407
+ it "should return true if the provider has no outstanding changes" do
408
+ user.stubs(:pending_changes => {})
409
+ user.has_pending_changes?.should be false
410
+ end
411
+
412
+ it "should return false if the provider has outstanding changes" do
413
+ user.stubs(:pending_changes => {
414
+ "last_name" => {"was" => "L", "became" => "T"}
415
+ })
416
+ user.has_pending_changes?.should be true
417
+ end
418
+
419
+ end
420
+
421
+
422
+
423
+ end
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'spork'
3
+ #uncomment the following line to use spork with the debugger
4
+ #require 'spork/ext/ruby-debug'
5
+
6
+ Spork.prefork do
7
+ # Loading more in this block will cause your tests to run faster. However,
8
+ # if you change any configuration or code from libraries loaded here, you'll
9
+ # need to restart spork for it take effect.
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
12
+
13
+ require 'rspec'
14
+ require 'requires_approval'
15
+
16
+ require 'ruby-debug'
17
+ Debugger.start
18
+
19
+ # Requires supporting files with custom matchers and macros, etc,
20
+ # in ./support/ and its subdirectories.
21
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
22
+
23
+ RSpec.configure do |config|
24
+ config.mock_with :mocha
25
+ config.treat_symbols_as_metadata_keys_with_true_values = true
26
+ config.filter_run :focus => true
27
+ config.run_all_when_everything_filtered = true
28
+
29
+ end
30
+ Mocha::Configuration.prevent(:stubbing_non_existent_method)
31
+ end
32
+
33
+ Spork.each_run do
34
+ # This code will be run each time you run your specs.
35
+
36
+ end
37
+
38
+ # --- Instructions ---
39
+ # Sort the contents of this file into a Spork.prefork and a Spork.each_run
40
+ # block.
41
+ #
42
+ # The Spork.prefork block is run only once when the spork server is started.
43
+ # You typically want to place most of your (slow) initializer code in here, in
44
+ # particular, require'ing any 3rd-party gems that you don't normally modify
45
+ # during development.
46
+ #
47
+ # The Spork.each_run block is run each time you run your specs. In case you
48
+ # need to load files that tend to change during development, require them here.
49
+ # With Rails, your application modules are loaded automatically, so sometimes
50
+ # this block can remain empty.
51
+ #
52
+ # Note: You can modify files loaded *from* the Spork.each_run block without
53
+ # restarting the spork server. However, this file itself will not be reloaded,
54
+ # so if you change any of the code inside the each_run block, you still need to
55
+ # restart the server. In general, if you have non-trivial code in this file,
56
+ # it's advisable to move it into a separate file so you can easily edit it
57
+ # without restarting spork. (For example, with RSpec, you could move
58
+ # non-trivial code into a file spec/support/my_helper.rb, making sure that the
59
+ # spec/support/* files are require'd from inside the each_run block.)
60
+ #
61
+ # Any code that is left outside the two blocks will be run during preforking
62
+ # *and* during each_run -- that's probably not what you want.
63
+ #
64
+ # These instructions should self-destruct in 10 seconds. If they don't, feel
65
+ # free to delete them.
@@ -0,0 +1 @@
1
+ Placeholder to add this directory to version control