requires_approval_rails_2 1.0.0

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.
@@ -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