Disappearing attributes... was I duped?


Showing a list of attributes that appear on either object A or it's parent object B should be really easy right?

I thought so, but then strange things started happening...

Here's the code:

  def get_full_list
    # start with attributes attached to this user
    all_attributes = self.attributes

	# build up an array of attribute codes
    attribute_codes =
    all_attributes.each do |a|
      attribute_codes << a.code

    # add attributes to be inherited from the parent
	# (i.e. not attached at user level)
    parent_attributes = self.parent.attributes
    parent_attributes.each do |a|
      if attribute_codes.index(a.code).nil?
        attribute_codes << a.code
        all_attributes << a

    return all_attributes

Now what's wrong with this code?

(Ok, there could be be plenty of things wrong with the code, but I want to focus on one point in particular. Feel free to add a comment below if you spot any other deficiencies).

The problem is that when I create a new attribute on the parent (from a web form not shown here) then the attribute magically migrates to the child object once the above code is executed - all I wanted to do was to get a list of all attributes attached to the child or parent, not to change any of the attributes at either level.

So why were the parent attributes magically moving over to the child? Especially since there is no save involved...

The answer to the main point (why did they move?) lies in this line:

    all_attributes = self.attributes

The solution is really, really simple, but it took me quite a while to work out what was really going on.

Rather than getting a copy of the array as I'd intended, I was actually getting the same array - i.e all_attributes became a reference to the real thing, so any changes to the elements in all_attributes were really changing elements in self.attributes.

So how can I get a copy of an array rather than a reference?

Just use the ruby core method dup. Simple as that.

.dup : "...produces a shallow copy of obj---the instance variables of obj are copied, but not the objects they reference..."

i.e. everything was solved once I changed the offending line to:

    all_attributes = self.attributes.dup

Now another problem, how can I justify to by boss the way I spent so much time implementing a 4-character fix???

| | |



RoRnoob said on 12-Nov-2009, "more...":
Actually I'm still surprised that the changes were saved to the database when there is no save command in my code...

Can anyone shed any light on this?

Else I guess I have to put it down to some other section of code forcing a save of the object.
Add your comment