You'll want to use save! and friends within the block, and catch
exceptions (ActiveRecord::RecordInvalid and
ActiveRecord::RecordNotSaved) to display errors.
--Matt Jones
AR doesn't automatically save associated records, but it's easy enough
to do it yourself.
Your models would end up looking like this:
# ------------ ALLOCATION -------------
class Allocation < ActiveRecord::Base
belongs_to :book
belongs_to :chapter
# note no validation here
end
# ----------- BOOK ---------------
class Book < ActiveRecord::Base
has_many :allocations
has_many :chapters, :through => :allocations
before_save :check_totals
def check_totals
sum = self.allocations.sum(:amount)
if !(self.amount == sum)
self.errors.add :amount, 'amounts do not match'
false
end
end
end
# ----------- CHAPTER ---------------
class Chapter < ActiveRecord::Base
has_many :allocations
has_many :books, :through => :allocations
end
With a controller action like this:
def update_stuff
@book = ... # get book instance
# do stuff to @book.allocations - don't use update_attributes, as
it will save the allocations
if @book.save
# success
else
# something went wrong
end
end
The false return value from check_totals will rollback the whole
implicit transaction that book.save is enclosed in
if the totals don't match up.
I'm not sure what the concern about ActiveScaffold is about - I
haven't looked at it in a lot of depth, but I doubt that
it supports the kind of multi-model form you'll need to update the
records the way you plan to. As it stands, it wouldn't
be possible to update either a Book or an Allocation independently.
The concept of "trusted" access methods is somewhat useless; if you
don't trust the code in your controllers, you have
a whole other problem. Even if ironclad validations could be set up,
all it takes is a call to save(false) to get past them...
--Matt