[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.

On Jul 12, 10:03 pm, Phoenix R. [email protected] wrote:

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

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!