问题
I know that the general order in which models are saved is the deepest child first, and then gradually up to the parent. But I'm wondering with respect to other callbacks, does it happen something along the lines of:
ChildA - before validation
ChildB - before validation
Parent - before validation
ChildA - after validation
ChildB - after validation
Parent - after validation
ChildA - before save
ChildB - before save
Parent - before save
...
OR along the lines of:
ChildA - before validation
ChildA - after validation
ChildA - before save
...
ChildB - before validation
ChildB - after validation
ChildB - before save
...
Parent - before validation
Parent - after validation
Parent - before save
...
The reason this is important is that I have callbacks that adjust attributes, and the adjustability of an attribute on a model depends on the attributes of other models.
One example is that I want the Parent to auto-set its status attribute to be Complete if ChildA and child B'sstatusattributes are bothCompleteand the children are bothvalid`.
I tried to test this using puts statements, but apparently, that leads to some weird behaviour (see this question: Nested form validation statements repeating multiple times), and I'm afraid it's not representative.
I definitely read the Rails Guides, but maybe I'm blind because I didn't see a reference to this anywhere...
回答1:
While putting this kind of state machine logic in callbacks might be tempting, it makes for a hard to understand code. Consider instead having a dedicated method gathering and mutating your data in a more straightforward way.
This would also help with data consistency and tests, as described in this blog post.
回答2:
Interesting question. By default callback defined in the parent is run first. prepend: true option allows you to tune that behaviour.
See "Ordering callbacks" section in Rails API. It's also worth checking "Inheritable callback queues" section, since redefining a method is not the same as using macros.
P.S. All stated above is valid at least for version 4.2.5.2
回答3:
By experimenting with rails I have encountered that the parent is validated first and then child but no rails core member have pronounced about this.
That's why you can move logic to parent:
class Sale
has_many :details
before_validation :evaluate_details
# validations
def evaluate_details
self.details.each do |detail|
detail.generate_info
detail.items.each do |item|
item.dance
end
end
end
end
class Detail
belongs_to :sale
has_many :items
# validations
def generate_info
# Do things
end
end
class Item
belongs_to :detail
# validations
def dance
# Dancing
end
end
This prevents multiple executions and manages the execution order.
PD: Also you can avoid the before_validation callback and call the method manually.
来源:https://stackoverflow.com/questions/38253386/rails-in-what-order-do-model-callbacks-happen-for-nested-parent-child-models