On Tue, Jan 13, 2009 at 1:28 AM, Greg Hauptmann <
[email protected]> wrote:
> Hi,
>
> QUESTION: How can establishing validation that spans multiple models be
> achieved in Rails? That is in such a fashion that it is not possible for a
> developer to break the validation via using any of the public model methods
> (e.g. update_attribute, save, create etc).
A developer can always break validation with something like
save_with_validation(false)
>
>
> EXAMPLE:
> * Concept: MAGAZINE can contain multiple ARTICLES, and an ARTICLE can be
> associated with multiple MAGAZINE (i.e. many to many). Cost of Magazine =
> Sum(Cost of Articles)
> * Tables:
> (a) magazines (has "cost" field)
> (b) articles_magazines (to map the many-to-many)
> (c) articles (has "total_cost" field)
Shouldn't the magazine have the total_cost field, and the article have a
cost field?
>
>
> BUSINESS RULE to be implemented: Not possible for a database update that
> would end up with a Magazine's "total_cost" not being equal to the
> Sum(associated articles "cost"s)
>
> ISSUES / QUESTIONS:
> (1) Assume would not try to implement rules at database constraint level???
> (2) Use of Model "before_create" - but I'm assuming here if the Article is
> generated (Article.new), and then validation occurs, the code has NOT yet
> got to the bit where it updates the Magazine?
> (3) Use of "after_create" - Add a check for both Magazine and Article
> perhaps here, noting the database record has been created by transaction NOT
> finalised yet. So would the following be the best way:
>
> -----example-------
> class Magazine < ActiveRecord::Base
> after_save :business_rule_validation
> def business_rule_validation
> sum_of_articles = << INSERT code that calculates SUM of Articles costs
> for all articles that are associated with the Magazine >>
> errors.add_to_base("business rules fail") if self.total_cost !=
> sum_of_articles
> end
> end
The after_save callback is not for validation - see
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
If you must validate use the validate method or and do your calculations and
validation in there.
>
> class Article < ActiveRecord::Base
> << Add Same Concept as per Magazine >>
> end
> -----example-------
>
> BUT wouldn't this fail, as it assumes the Article create/update/delete and
> the Magazine create/update/delete is in the SAME transaction no??? Does
> this mean you really have to create an overarching facade that handles
> creates/updates/deletes for Article/Magazines and somehow hide the normal
> per model save/update/delete???
>
> --
> Greg
> http://blog.gregnet.org/
>
>
>
> >
>
Instead of storing the total cost and doing all this validation, I'd
calculate the magazine total_cost as needed
class Magazine < ActiveRecord::Base
def total_cost
articles.to_a.sum(&:cost)
end
end
--
Andrew Timberlake
http://ramblingsonrails.com
http://www.linkedin.com/in/andrewtimberlake
"I have never let my schooling interfere with my education" - Mark Twain
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Talk" 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-talk?hl=en
-~----------~----~----~----~------~----~------~--~---