association_proxy.is_a?(Array), acts like an array, but doesn't save like an array


Sep 26, 2007
So, how many times have you had the urge to write:
@post.comments.reject!(&:spam?)
@post.save
Lots? Me too. So, I think it's worth clearing the air on our good friend association proxy. He really, really wants you to believe he's an array. He'll even tell you he is.
assert @post.comments.is_a?(Array)
But, don't believe him, because a lot of his array functionality is useless to us. Your favourite rubyisms (reject!, select!, etc) will modify the collection, but will not modify the associations. This test passes:
def test_association_proxy_really_looks_like_an_array_but_it_isnt
  assert Post.find(1).comments.is_a?(Array)
  
  assert Post.find(1).comments.select(&:spam?).length > 0
    
  post = Post.find(1)
  post.comments.reject!(&:spam?)
  post.save!
  
  assert_equal [], post.comments.select(&:spam?)
  assert Post.find(1).comments.select(&:spam?).length > 0
end
Instead, of course, you have to use the delete method.
post.comments.delete(post.comments.select(&:spam?))
Association proxy is tricky.