From 572323135f235cc43e8a5bbafa3a634b4ec71ba8 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 7 Oct 2009 23:50:30 +0100 Subject: Allow accepts_nested_attributes_for :reject_if option accept symbols for using a method Conflicts: activerecord/lib/active_record/nested_attributes.rb --- .../lib/active_record/nested_attributes.rb | 39 ++++++++++++++++++---- activerecord/test/cases/nested_attributes_test.rb | 20 +++++++++++ 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 id key that matches an already # associated record, the matching record will be modified: # @@ -179,10 +195,11 @@ module ActiveRecord # _destroy 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 _destroy value that evaluates to true. # Passing :all_blank 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 :reject_if 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") -- cgit v1.2.3