-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix autosave for accepts_nested_attributes_for #5725
Fix autosave for accepts_nested_attributes_for #5725
Conversation
9a0a3e9
to
41dfff4
Compare
eefd57e
to
f1aeefa
Compare
|
@kodawill two points here. First, please make a test case which demonstrates why this change is needed. For example:
Second, (assuming this is a legitimate issue per #1) I don't think that specifying |
…ed_attributes_for
f1aeefa
to
86192bd
Compare
@johnnyshields first of all thank you for your feedback. I have reverted previous changes and instead, as you suggested, wrote a failing spec demonstrating the possible bug for autosaving. If I understand you correctly, auto-save logic should only be invoked if |
@kodawill re: your comment:
Let's start with specs that describe the end-result behavior when setting nested attributes, i.e., "is the nested model actually being persisted in the database under X conditions." The specs you have currently make assertions around whether After we describe the desired behavior, then we can consider what the ideal approach is to achieve it (i.e. use autosave, or use some other logic.) |
@johnnyshields Added another test (failing) to describe the desired behavior. |
And here is my proposal for the fix: --- a/lib/mongoid/attributes/nested.rb
+++ b/lib/mongoid/attributes/nested.rb
@@ -47,6 +47,7 @@ module Mongoid
# enable it.
def accepts_nested_attributes_for(*args)
options = args.extract_options!.dup
+ autosave_via_nested_attributes = options[:autosave]
options[:autosave] = true if options[:autosave].nil?
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
@@ -55,7 +56,7 @@ module Mongoid
self.nested_attributes["#{name}_attributes"] = meth
association = relations[name.to_s]
raise Errors::NestedAttributesMetadataNotFound.new(self, name) unless association
- autosave_nested_attributes(association) if options[:autosave]
+ autosave_nested_attributes(association, autosave_via_nested_attributes) if options[:autosave]
re_define_method(meth) do |attrs|
_assigning do
@@ -78,12 +79,13 @@ module Mongoid
# Person.autosave_nested_attributes(metadata)
#
# @param [ Mongoid::Association::Relatable ] association The existing association metadata.
- def autosave_nested_attributes(association)
+ # @param [ true | false ] autosave_via_nested_attributes Autosave once options[:autosave] is true in accepts_nested_attributes_for
+ def autosave_nested_attributes(association, autosave_via_nested_attributes = false)
# In order for the autosave functionality to work properly, the association needs to be
# marked as autosave despite the fact that the option isn't present. Because the method
# Association#autosave? is implemented by checking the autosave option, this is the most
# straightforward way to mark it.
- if association.autosave? || (association.options[:autosave].nil? && !association.embedded?)
+ if association.autosave? || ((association.options[:autosave].nil? || autosave_via_nested_attributes) && !association.embedded?)
association.options[:autosave] = true
Association::Referenced::AutoSave.define_autosave!(association)
end |
Another option by using another (additional) method: --- a/lib/mongoid/attributes/nested.rb
+++ b/lib/mongoid/attributes/nested.rb
@@ -46,6 +46,7 @@ module Mongoid
# association. Note that since the default is true, setting autosave to nil will still
# enable it.
def accepts_nested_attributes_for(*args)
+ autosave_nested_attrs = autosave_nested_attribute?(args.dup)
options = args.extract_options!.dup
options[:autosave] = true if options[:autosave].nil?
@@ -55,7 +56,7 @@ module Mongoid
self.nested_attributes["#{name}_attributes"] = meth
association = relations[name.to_s]
raise Errors::NestedAttributesMetadataNotFound.new(self, name) unless association
- autosave_nested_attributes(association) if options[:autosave]
+ autosave_nested_attributes(association, autosave_nested_attrs) if options[:autosave]
re_define_method(meth) do |attrs|
_assigning do
@@ -78,16 +79,32 @@ module Mongoid
# Person.autosave_nested_attributes(metadata)
#
# @param [ Mongoid::Association::Relatable ] association The existing association metadata.
- def autosave_nested_attributes(association)
+ # @param [ true | false ] autosave_nested_attrs Autosave once options[:autosave] is true in accepts_nested_attributes_for
+ def autosave_nested_attributes(association, autosave_nested_attrs = false)
# In order for the autosave functionality to work properly, the association needs to be
# marked as autosave despite the fact that the option isn't present. Because the method
# Association#autosave? is implemented by checking the autosave option, this is the most
# straightforward way to mark it.
- if association.autosave? || (association.options[:autosave].nil? && !association.embedded?)
+ if association.autosave? || ((association.options[:autosave].nil? || autosave_nested_attrs) && !association.embedded?)
association.options[:autosave] = true
Association::Referenced::AutoSave.define_autosave!(association)
end
end
+
+
+
+ # This method should be used to detect whether a nested attribute association
+ # is autosave or not when parent document is saved. Nested attribute association
+ # is autosave if `autosave` option in #accepts_nested_attributes_for is explicitly set to true.
+ #
+ # @param [ Hash ] args The options being passed in accepts_nested_attributes_for.
+ #
+ # @return [ true | false ] Whether nested attribute is to be autosave
+ # on parent document save or not.
+ def autosave_nested_attribute?(args)
+ options = args.extract_options!
+ options[:autosave] == true
+ end
end
end
end |
@jamis it's fine to close this PR. I will take it over and re-raise. |
Summary
This PR attempts to automatically save associated documents for referenced (i.e., non-embedded) associations when the parent is saved even if
autosave
option set tofalse
as long as associated documents are declared as nested attributes viaaccepts_nested_attributes_for
andautosave
is set totrue
.