diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index e62d77a60d..7272741329 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Association collections have an _ids reader method to match the existing writer for collection_select convenience (e.g. employee.task_ids). The writer method skips blank ids so you can safely do @employee.task_ids = params[:tasks] without checking every time for an empty list or blank values. #1887, #5780 [Michael Schuerig] + * Add an attribute reader method for ActiveRecord::Base.observers [Rick Olson] * Deprecation: count class method should be called with an options hash rather than two args for conditions and joins. #6287 [Bob Silva] diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 60f0a137b0..c73b5db51e 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -916,8 +916,13 @@ module ActiveRecord association end + define_method("#{reflection.name.to_s.singularize}_ids") do + send(reflection.name).map(&:id) + end + define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value| - send("#{reflection.name}=", reflection.class_name.constantize.find(new_value)) + ids = (new_value || []).reject { |nid| nid.blank? } + send("#{reflection.name}=", reflection.class_name.constantize.find(ids)) end end diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb index b843f5bdf5..a75f708ea7 100755 --- a/activerecord/test/associations_test.rb +++ b/activerecord/test/associations_test.rb @@ -934,6 +934,10 @@ class HasManyAssociationsTest < Test::Unit::TestCase assert firm.clients.include?(Client.find_by_name("New Client")) end + def test_get_ids + assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids + end + def test_assign_ids firm = Firm.new("name" => "Apple") firm.client_ids = [companies(:first_client).id, companies(:second_client).id] @@ -942,6 +946,16 @@ class HasManyAssociationsTest < Test::Unit::TestCase assert_equal 2, firm.clients.length assert firm.clients.include?(companies(:second_client)) end + + def test_assign_ids_ignoring_blanks + firm = Firm.new("name" => "Apple") + firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, ''] + firm.save + firm.reload + assert_equal 2, firm.clients.length + assert firm.clients.include?(companies(:second_client)) + end + end class BelongsToAssociationsTest < Test::Unit::TestCase @@ -1735,4 +1749,29 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size end + + def test_get_ids + assert_equal [projects(:active_record).id, projects(:action_controller).id], developers(:david).project_ids + assert_equal [projects(:active_record).id], developers(:jamis).project_ids + end + + def test_assign_ids + developer = Developer.new("name" => "Joe") + developer.project_ids = [projects(:active_record).id, projects(:action_controller).id] + developer.save + developer.reload + assert_equal 2, developer.projects.length + assert_equal projects(:active_record), developer.projects[0] + assert_equal projects(:action_controller), developer.projects[1] + end + + def test_assign_ids_ignoring_blanks + developer = Developer.new("name" => "Joe") + developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, ''] + developer.save + developer.reload + assert_equal 2, developer.projects.length + assert_equal projects(:active_record), developer.projects[0] + assert_equal projects(:action_controller), developer.projects[1] + end end