diff options
-rw-r--r-- | activerecord/lib/active_record/nested_attributes.rb | 39 | ||||
-rw-r--r-- | activerecord/test/cases/nested_attributes_test.rb | 20 | ||||
-rw-r--r-- | activerecord/test/models/pirate.rb | 4 |
3 files changed, 57 insertions, 6 deletions
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 3c8140816c..654e91bece 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -127,6 +127,22 @@ module ActiveRecord # member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!' # member.posts.second.title # => 'The egalitarian assumption of the modern citizen' # + # Alternatively, :reject_if also accepts a symbol for using methods: + # + # class Member < ActiveRecord::Base + # has_many :posts + # accepts_nested_attributes_for :posts, :reject_if => :new_record? + # end + # + # class Member < ActiveRecord::Base + # has_many :posts + # accepts_nested_attributes_for :posts, :reject_if => :reject_posts + # + # def reject_posts(attributed) + # attributed['title].blank? + # end + # end + # # If the hash contains an <tt>id</tt> key that matches an already # associated record, the matching record will be modified: # @@ -179,10 +195,11 @@ module ActiveRecord # <tt>_destroy</tt> key and a value that evaluates to +true+ # (eg. 1, '1', true, or 'true'). This option is off by default. # [:reject_if] - # Allows you to specify a Proc that checks whether a record should be - # built for a certain attribute hash. The hash is passed to the Proc - # and the Proc should return either +true+ or +false+. When no Proc - # is specified a record will be built for all attribute hashes that + # Allows you to specify a Proc or a Symbol pointing to a method + # that checks whether a record should be built for a certain attribute + # hash. The hash is passed to the supplied Proc or the method + # and it should return either +true+ or +false+. When no :reject_if + # is specified, a record will be built for all attribute hashes that # do not have a <tt>_destroy</tt> value that evaluates to true. # Passing <tt>:all_blank</tt> instead of a Proc will create a proc # that will reject a record where all the attributes are blank. @@ -351,8 +368,18 @@ module ActiveRecord # has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this # association and evaluates to +true+. def reject_new_record?(association_name, attributes) - has_destroy_flag?(attributes) || - self.class.reject_new_nested_attributes_procs[association_name].try(:call, attributes) + has_destroy_flag?(attributes) || call_reject_if(association_name, attributes) + end + + def call_reject_if(association_name, attributes) + callback = self.class.reject_new_nested_attributes_procs[association_name] + + case callback + when Symbol + method(callback).arity == 0 ? send(callback) : send(callback, attributes) + when Proc + callback.try(:call, attributes) + end end end end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 721792132c..bf9aa4e65f 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -84,6 +84,26 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase ship = Ship.create!(:name => 'Nights Dirty Lightning') ship._delete end + + def test_reject_if_method_without_arguments + Pirate.accepts_nested_attributes_for :ship, :reject_if => :new_record? + + pirate = Pirate.new(:catchphrase => "Stop wastin' me time") + pirate.ship_attributes = { :name => 'Black Pearl' } + assert_no_difference('Ship.count') { pirate.save! } + end + + def test_reject_if_method_with_arguments + Pirate.accepts_nested_attributes_for :ship, :reject_if => :reject_empty_ships_on_create + + pirate = Pirate.new(:catchphrase => "Stop wastin' me time") + pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true } + assert_no_difference('Ship.count') { pirate.save! } + + # pirate.reject_empty_ships_on_create returns false for saved records + pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true } + assert_difference('Ship.count') { pirate.save! } + end end class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index 3d7c4bc48a..05c5b666ae 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -45,6 +45,10 @@ class Pirate < ActiveRecord::Base @ship_log ||= [] end + def reject_empty_ships_on_create(attributes) + attributes.delete('_reject_me_if_new').present? && new_record? + end + private def log_before_add(record) log(record, "before_adding_method") |