dependent_protect 0.0.3 → 0.0.4

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/Gemfile CHANGED
@@ -8,4 +8,5 @@ group :development, :test do
8
8
  gem 'simplecov'
9
9
  gem 'simplecov-rcov'
10
10
  gem 'sqlite3'
11
+ gem 'activerecord', '2.3.14'
11
12
  end
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'dependent_protect'
16
- s.version = '0.0.3'
17
- s.date = '2012-04-29'
16
+ s.version = '0.0.4'
17
+ s.date = '2012-06-10'
18
18
  s.rubyforge_project = 'dependent_protect'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -66,6 +66,7 @@ Gem::Specification.new do |s|
66
66
  gemfiles/rails2.gemfile
67
67
  gemfiles/rails3.gemfile
68
68
  lib/dependent_protect.rb
69
+ lib/dependent_protect/delete_restriction_error.rb
69
70
  spec/dependent_protect_spec.rb
70
71
  spec/schema.rb
71
72
  spec/spec_helper.rb
@@ -0,0 +1,31 @@
1
+ module ActiveRecord
2
+ # This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
3
+ # (has_many, has_one) when there is at least 1 child associated instance.
4
+ # ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
5
+ class DeleteRestrictionError < ActiveRecordError #:nodoc:
6
+ def initialize(reflection, record)
7
+ @reflection = reflection
8
+ @record = record
9
+ super(basic_message)
10
+ end
11
+
12
+ def basic_message
13
+ single = @reflection.class_name.to_s.underscore.gsub('_', ' ')
14
+ if [:has_many, :has_and_belongs_to_many].include?(@reflection.macro)
15
+ count = @record.send(@reflection.name).count
16
+ type = count == 1 ? single : single.pluralize
17
+ exist = (count == 1 ? 'exists' : 'exist')
18
+ "Cannot delete record because #{count} dependent #{type} #{exist}"
19
+ else
20
+ "Cannot delete record because dependent #{single} exists"
21
+ end
22
+ end
23
+
24
+ def detailed_message
25
+ count = @record.send(@reflection.name).count
26
+ examples = @record.send(@reflection.name).all(:limit => 5).map{|o| "#{o.id}: #{o.to_s}"}
27
+ examples[4] = "...and #{count - 4} more" if count > 5
28
+ basic_message + "\n\n\nThese include:\n#{examples.join("\n")}"
29
+ end
30
+ end
31
+ end
@@ -1,19 +1,15 @@
1
1
  # DependentProtect
2
2
  #
3
3
  require 'active_record'
4
+ require 'dependent_protect/delete_restriction_error'
4
5
 
5
6
  module DependentProtect
6
- VERSION = '0.0.3'
7
-
8
- DESTROY_PROTECT_ERROR_MESSAGE = 'Cant destroy because there are dependent_count dependent_type dependent on dependee_type dependee.\n\n\nThese include:\ndependent_examples'
7
+ VERSION = '0.0.4'
9
8
 
10
9
  def self.included(base)
11
10
  super
12
11
  base.extend(ClassMethods)
13
12
 
14
- klass = Class.new(ActiveRecord::ActiveRecordError)
15
- ActiveRecord.const_set('DependencyError', klass)
16
-
17
13
  base.class_eval do
18
14
  class << self
19
15
  alias_method_chain :has_one, :protect
@@ -47,49 +43,30 @@ module DependentProtect
47
43
 
48
44
  private
49
45
  def add_dependency_callback!(reflection, options)
50
- # This would break if has_many :dependent behaviour changes. One
51
- # solution is removing both the second when and the else branches but
52
- # the exception message wouldn't be exact.
53
- condition = if reflection.collection?
54
- "record.#{reflection.name}.empty?"
55
- else
56
- "record.#{reflection.name}.nil?"
57
- end
58
-
59
46
  case reflection.options[:dependent]
60
47
  when :rollback
61
48
  options.delete(:dependent)
62
- module_eval "before_destroy, :protect_rollback, :unless => proc{ |record| #{condition} }"
63
- when :raise
49
+ method_name = "dependent_rollback_for_#{reflection.name}".to_sym
50
+ define_method(method_name) do
51
+ method = reflection.collection? ? :empty? : :nil?
52
+ unless send(reflection.name).send(method)
53
+ raise ActiveRecord::Rollback
54
+ end
55
+ end
56
+ before_destroy method_name
57
+ when :restrict
64
58
  options.delete(:dependent)
65
- error = reflection.collection? ? dependency_error(reflection) : "Cannot remove as the associated object is dependent on this."
66
- module_eval <<-METHOD
67
- def protect_raise_#{reflection.name}
68
- raise ActiveRecord::DependencyError, "#{error}"
69
- end
70
- METHOD
71
- module_eval "before_destroy :protect_raise_#{reflection.name}, :unless => proc{ |record| #{condition} }"
59
+ method_name = "dependent_restrict_for_#{reflection.name}".to_sym
60
+ define_method(method_name) do
61
+ method = reflection.collection? ? :empty? : :nil?
62
+ unless send(reflection.name).send(method)
63
+ raise ActiveRecord::DeleteRestrictionError.new(reflection, self)
64
+ end
65
+ end
66
+ before_destroy method_name
72
67
  end
73
68
  end
74
-
75
- def protect_rollback
76
- raise ActiveRecord::Rollback
77
- end
78
-
79
- def dependency_error(reflection)
80
- # TODO: gotta be a more easier approach!
81
- count_code = "#{reflection.name}.count"
82
- first_five_code = reflection.name.to_s+'.first(5).map{|o| "#{o.id}: #{o.to_s}"}'
83
- DESTROY_PROTECT_ERROR_MESSAGE.
84
- gsub('dependent_type', reflection.class_name.to_s.underscore.gsub('_', ' ').pluralize).
85
- gsub('dependent_examples', '#{(' + first_five_code + ' + [("...and #{' + count_code + ' - 5} more" if ' + count_code + ' > 5)]).join("\n")}').
86
- gsub('dependent_count', '#{' + count_code + '}').
87
- gsub('dependee_type', '#{self.class.to_s.underscore.gsub(\'_\', \' \')}').
88
- gsub('dependee', '#{self}')
89
- end
90
-
91
69
  end
92
70
  end
93
71
 
94
-
95
72
  ActiveRecord::Base.send(:include, DependentProtect)
@@ -14,27 +14,44 @@ end
14
14
 
15
15
  class Order < ActiveRecord::Base
16
16
  belongs_to :category
17
- has_one :order_invoice, :dependent => :raise
17
+ has_one :order_invoice, :dependent => :restrict
18
+ def to_s
19
+ "Order #{id}"
20
+ end
18
21
  end
19
22
 
20
23
  class Category < ActiveRecord::Base
21
- has_many :orders, :dependent => :raise
24
+ has_many :orders, :dependent => :restrict
25
+ def to_s
26
+ "Category #{id}"
27
+ end
22
28
  end
23
29
 
24
30
  describe DependentProtect do
25
31
  it 'should restrict has_many relationships' do
26
32
  category = Category.create!
27
- order = Order.create!(:category => category)
28
- lambda{category.reload.destroy}.should raise_error(ActiveRecord::DependencyError)
29
-
30
- order.destroy
33
+ 5.times { Order.create!(:category => category) }
34
+ lambda{category.reload.destroy}.should raise_error(ActiveRecord::DeleteRestrictionError, 'Cannot delete record because 5 dependent orders exist')
35
+ begin
36
+ category.destroy
37
+ rescue ActiveRecord::DeleteRestrictionError => e
38
+ e.detailed_message.should == "Cannot delete record because 5 dependent orders exist\n\n\nThese include:\n1: Order 1\n2: Order 2\n3: Order 3\n4: Order 4\n5: Order 5"
39
+ end
40
+ 1.times { Order.create!(:category => category) }
41
+ begin
42
+ category.destroy
43
+ rescue ActiveRecord::DeleteRestrictionError => e
44
+ e.detailed_message.should == "Cannot delete record because 6 dependent orders exist\n\n\nThese include:\n1: Order 1\n2: Order 2\n3: Order 3\n4: Order 4\n...and 2 more"
45
+ end
46
+
47
+ Order.destroy_all
31
48
  lambda{category.reload.destroy}.should_not raise_error
32
49
  end
33
50
 
34
51
  it 'should restrict has_one relationships' do
35
52
  order = Order.create!
36
53
  order_invoice = OrderInvoice.create!(:order => order)
37
- lambda{order.reload.destroy}.should raise_error(ActiveRecord::DependencyError)
54
+ lambda{order.reload.destroy}.should raise_error(ActiveRecord::DeleteRestrictionError, 'Cannot delete record because dependent order invoice exists')
38
55
 
39
56
  order_invoice.destroy
40
57
  lambda{order.reload.destroy}.should_not raise_error
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependent_protect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-29 00:00:00.000000000 Z
12
+ date: 2012-06-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -50,6 +50,7 @@ files:
50
50
  - gemfiles/rails2.gemfile
51
51
  - gemfiles/rails3.gemfile
52
52
  - lib/dependent_protect.rb
53
+ - lib/dependent_protect/delete_restriction_error.rb
53
54
  - spec/dependent_protect_spec.rb
54
55
  - spec/schema.rb
55
56
  - spec/spec_helper.rb