[R3B4] errors[:base] = appends, doesn't "set" - bug, feature, or "error 18"?

If you haven't heard, an "error 18" means "the error is 18 inches from the screen." Which would mean that I totally get that this could just be me being stupid.

However, for some reason I'm thinking this violates the normal behavior of an Array object, so I'm curious as to if I'm doing something wrong here, or if something really is buggy in - or a feature of - Rails 3.

So here's the deal: I want to SET - not append to - the errors array on certain conditions in my application. Through testing I've discovered that when you use the = operator on errors[:base], it *appends* to the array instead of replacing it. This is totally different from a standard Array object, yet errors[:base].class returns "Array". Observe:

Loading development environment (Rails 3.0.0.beta4) ree-1.8.7-2010.02 > u = User.new => #<User id: nil, blah blah blah stuff for new user object> ree-1.8.7-2010.02 > u.errors[:base] = ["Test"] => ["Test"] ree-1.8.7-2010.02 > u.errors[:base] = ["Testing"] => ["Testing"] ree-1.8.7-2010.02 > u.errors[:base] => [["Test"], ["Testing"]] ree-1.8.7-2010.02 > u.errors[:base].class => Array ree-1.8.7-2010.02 > x = => ree-1.8.7-2010.02 > x = ["test"] => ["test"] ree-1.8.7-2010.02 > x = ["testing"] => ["testing"]

As you can see, instantiating a normal Array object and then calling the = operator *replaces* the contents of the array with the new array, a pretty standard and expected pattern. But doing the same thing on errors[:base] of an ActiveRecord object *appends* to the array, even though it's class is Array.

What could I be doing wrong here? Or is this just a feature of Rails 3? Should I submit a ticket via Lighthouse? Again, I'm fully willing to accept that I f'd up here. so feel free to tell me what I'm doing wrong. Thanks.

It is a feature. The thing that you are missing is that you're not using = on an array[1], you're calling the = method on the errors object which has overridden = to append stuff. A more typical usage with validations is that various errors are added to an attribute (or to base) as time goes on. You can see what's being done at http://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb which reveals that the original = method is aliased as set

Fred

[1] Being nitpicky, = is one of the operators in ruby that is not implemented via a method so writing "calling it" isn't quite write. Also writing x= ["test"] does not replace the contents of an array - it just points the local variable x at a new object.

It is a feature. The thing that you are missing is that you're not using = on an array[1], you're calling the = method on the errors object which has overridden = to append stuff. A more typical usage with validations is that various errors are added to an attribute (or to base) as time goes on. You can see what's being done athttp://github.com/rails/rails/blob/master/activemodel/lib/active_modeā€¦ which reveals that the original = method is aliased as set

Thank you, Fred. As always, you are the MAN. I had a feeling it was something like this, but I just plain haven't noticed this behavior before, as I always use errors[:base] for one error at a time, and errors[:attribute] for each individual attribute for which there's an error. Just a practice I've used for a while, but this was obviously an "error 18" on my part, so thanks for pointing that out.

[1] Being nitpicky, = is one of the operators in ruby that is not implemented via a method so writing "calling it" isn't quite write. Also writing x= ["test"] does not replace the contents of an array - it just points the local variable x at a new object.

Thank you for the lesson here! I knew the second part (about passing it a memory pointer to a new object), but I wasn't even thinking about the nomenclature of "calling" versus ...using? Not sure what else to call it either. Anyway, I appreciate the information - thanks again!