Hi, (no luck on the user forum so I'm hoping I can ask here)
I'm trying to get a simple cross-model business rule working. In this case
the rule is (see below for models overview):
* Rule = Sum(allocations amount, for a book) = Book Amount
ISSUE: The issue is in using after_create is that either the book or
allocation is saved before the other. The only way I can see to make this
work is to have a check just prior to COMMIT, where all records are visible
within the DB and your final checks can be run (and rolled back if there is
problem). Hence my question:
QUESTION: Is there an "before_commit" hook somewhere in Rails? (or how else
would I satisfy my requirement)
----------------------------------------------------------------------------------
Macintosh-2:after_create_test greg$ spec spec/model/all_in_one_test_spec.rb
============= NEW TEST ======================
BOOK: after_save
F============= NEW TEST ======================
CHAPTER: after_save
.============= NEW TEST ======================
BOOK: after_save
.
1)
RuntimeError in 'Book should save if allocation amount == book amount'
amounts do NOT match
./spec/model/all_in_one_test_spec.rb:26:in `after_save_check'
./spec/model/all_in_one_test_spec.rb:51:
Finished in 0.061092 seconds
3 examples, 1 failure
----------------------------------------------------------------------------------
Macintosh-2:after_create_test greg$ cat -n
spec/model/all_in_one_test_spec.rb
1 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
3 # ------------ ALLOCATION -------------
4 class Allocation < ActiveRecord::Base
5 belongs_to :book
6 belongs_to :chapter
7
8 after_save :after_save_check
9 def after_save_check
10 puts "ALLOCATION: after_save"
11 b = self.book
12 sum = b.allocations.collect{|i| i.amount}.inject(0){|sum, n| sum
+ n }
13 raise("amounts do NOT match") if !(b.amount == sum)
14 end
15 end
16
17 # ----------- BOOK ---------------
18 class Book < ActiveRecord::Base
19 has_many :allocations
20 has_many :chapters, :through => :allocations
21
22 after_save :after_save_check
23 def after_save_check
24 puts "BOOK: after_save"
25 sum = self.allocations.collect{|i| i.amount}.inject(0){|sum, n|
sum + n }
26 raise "amounts do NOT match" if !(self.amount == sum)
27 end
28
29 end
30 # ----------- CHAPTER ---------------
31 class Chapter < ActiveRecord::Base
32 has_many :allocations
33 has_many :books, :through => :allocations
34
35 after_save :after_save_check
36 def after_save_check
37 puts "CHAPTER: after_save"
38 end
39
40 end
41
42 # --------- RSPEC (BOOK) ------------
43 describe Book do
44 before(:each) do
45 puts "============= NEW TEST ======================"
46 @b = Book.new(:amount => 100)
47 @c = Chapter.new()
48 end
49
50 it "should save if allocation amount == book amount" do
51 @b.save!
52 @c.save!
53 Allocation.create!(:book_id => @b.id, :chapter_id => @c.id,
:amount => 100)
54 end
55
56 it "should raise database exception if try to save allocation
prior to book" do
57 lambda {
58 @c.save!
59 Allocation.create!(:book_id => @b.id, :chapter_id => @c.id,
:amount => 100)
60 @b.save!
61 }.should raise_error
62 end
63
64 it "should raise error if allocation amount != book amount" do
65 lambda {
66 @b.save!
67 @c.save!
68 Allocation.create!(:book_id => @b.id, :chapter_id => @c.id,
:amount => 90)
69 }.should raise_error
70 end
71
72
73 end
74
----------------------------------------------------------------------------------
ActiveRecord::Schema.define(:version => 20090123000614) do
create_table "allocations", :force => true do |t|
t.integer "book_id", :null => false
t.integer "chapter_id", :null => false
t.integer "amount", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "books", :force => true do |t|
t.integer "amount", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "chapters", :force => true do |t|
t.datetime "created_at"
t.datetime "updated_at"
end
end
----------------------------------------------------------------------------------
--
Greg
http://blog.gregnet.org/
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Core" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/rubyonrails-core?hl=en
-~----------~----~----~----~------~----~------~--~---