Skip to content

Commit

Permalink
Define autosave association validation methods only when needed. [#3161
Browse files Browse the repository at this point in the history
… state:resolved]

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
  • Loading branch information
kovyrin authored and alloy committed Sep 12, 2009
1 parent 580ec0d commit 938c0ee
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 7 deletions.
13 changes: 10 additions & 3 deletions activerecord/lib/active_record/autosave_association.rb
Expand Up @@ -158,7 +158,7 @@ def #{type}(name, options = {})
def add_autosave_association_callbacks(reflection)
save_method = "autosave_associated_records_for_#{reflection.name}"
validation_method = "validate_associated_records_for_#{reflection.name}"
validate validation_method
force_validation = (reflection.options[:validate] == true || reflection.options[:autosave] == true)

case reflection.macro
when :has_many, :has_and_belongs_to_many
Expand All @@ -169,7 +169,10 @@ def add_autosave_association_callbacks(reflection)
after_create save_method
after_update save_method

define_method(validation_method) { validate_collection_association(reflection) }
if force_validation || (reflection.macro == :has_many && reflection.options[:validate] != false)
define_method(validation_method) { validate_collection_association(reflection) }
validate validation_method
end
else
case reflection.macro
when :has_one
Expand All @@ -179,7 +182,11 @@ def add_autosave_association_callbacks(reflection)
define_method(save_method) { save_belongs_to_association(reflection) }
before_save save_method
end
define_method(validation_method) { validate_single_association(reflection) }

if force_validation
define_method(validation_method) { validate_single_association(reflection) }
validate validation_method
end
end
end
end
Expand Down
115 changes: 115 additions & 0 deletions activerecord/test/cases/autosave_association_test.rb
Expand Up @@ -1056,3 +1056,118 @@ def setup

include AutosaveAssociationOnACollectionAssociationTests
end

class TestAutosaveAssociationValidationsOnAHasManyAssocication < ActiveRecord::TestCase
self.use_transactional_fixtures = false

def setup
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
@pirate.birds.create(:name => 'cookoo')
end

test "should automatically validate associations" do
assert @pirate.valid?
@pirate.birds.each { |bird| bird.name = '' }

assert !@pirate.valid?
end
end

class TestAutosaveAssociationValidationsOnAHasOneAssocication < ActiveRecord::TestCase
self.use_transactional_fixtures = false

def setup
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
@pirate.create_ship(:name => 'titanic')
end

test "should automatically validate associations with :validate => true" do
assert @pirate.valid?
@pirate.ship.name = ''
assert !@pirate.valid?
end

test "should not automatically validate associations without :validate => true" do
assert @pirate.valid?
@pirate.non_validated_ship.name = ''
assert @pirate.valid?
end
end

class TestAutosaveAssociationValidationsOnABelongsToAssocication < ActiveRecord::TestCase
self.use_transactional_fixtures = false

def setup
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
end

test "should automatically validate associations with :validate => true" do
assert @pirate.valid?
@pirate.parrot = Parrot.new(:name => '')
assert !@pirate.valid?
end

test "should not automatically validate associations without :validate => true" do
assert @pirate.valid?
@pirate.non_validated_parrot = Parrot.new(:name => '')
assert @pirate.valid?
end
end

class TestAutosaveAssociationValidationsOnAHABTMAssocication < ActiveRecord::TestCase
self.use_transactional_fixtures = false

def setup
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
end

test "should automatically validate associations with :validate => true" do
assert @pirate.valid?
@pirate.parrots = [ Parrot.new(:name => 'popuga') ]
@pirate.parrots.each { |parrot| parrot.name = '' }
assert !@pirate.valid?
end

test "should not automatically validate associations without :validate => true" do
assert @pirate.valid?
@pirate.non_validated_parrots = [ Parrot.new(:name => 'popuga') ]
@pirate.non_validated_parrots.each { |parrot| parrot.name = '' }
assert @pirate.valid?
end
end

class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCase
self.use_transactional_fixtures = false

def setup
@pirate = Pirate.new
end

test "should generate validation methods for has_many associations" do
assert @pirate.respond_to?(:validate_associated_records_for_birds)
end

test "should generate validation methods for has_one associations with :validate => true" do
assert @pirate.respond_to?(:validate_associated_records_for_ship)
end

test "should not generate validation methods for has_one associations without :validate => true" do
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_ship)
end

test "should generate validation methods for belongs_to associations with :validate => true" do
assert @pirate.respond_to?(:validate_associated_records_for_parrot)
end

test "should not generate validation methods for belongs_to associations without :validate => true" do
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_parrot)
end

test "should generate validation methods for HABTM associations with :validate => true" do
assert @pirate.respond_to?(:validate_associated_records_for_parrots)
end

test "should not generate validation methods for HABTM associations without :validate => true" do
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_parrots)
end
end
9 changes: 6 additions & 3 deletions activerecord/test/models/pirate.rb
@@ -1,6 +1,8 @@
class Pirate < ActiveRecord::Base
belongs_to :parrot
has_and_belongs_to_many :parrots
belongs_to :parrot, :validate => true
belongs_to :non_validated_parrot, :class_name => 'Parrot'
has_and_belongs_to_many :parrots, :validate => true
has_and_belongs_to_many :non_validated_parrots, :class_name => 'Parrot'
has_and_belongs_to_many :parrots_with_method_callbacks, :class_name => "Parrot",
:before_add => :log_before_add,
:after_add => :log_after_add,
Expand All @@ -16,7 +18,8 @@ class Pirate < ActiveRecord::Base
has_many :treasure_estimates, :through => :treasures, :source => :price_estimates

# These both have :autosave enabled because accepts_nested_attributes_for is used on them.
has_one :ship
has_one :ship, :validate => true
has_one :non_validated_ship, :class_name => 'Ship'
has_many :birds
has_many :birds_with_method_callbacks, :class_name => "Bird",
:before_add => :log_before_add,
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/models/ship.rb
@@ -1,7 +1,7 @@
class Ship < ActiveRecord::Base
self.record_timestamps = false

belongs_to :pirate
belongs_to :pirate, :validate => true
has_many :parts, :class_name => 'ShipPart', :autosave => true

accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
Expand Down

0 comments on commit 938c0ee

Please sign in to comment.