13-Nov-2009
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 = Array.new
all_attributes.each do |a|
attribute_codes << a.code
end
# 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
end
end
return all_attributes
end
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???
Comments
| RoRnoob said on 13-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. |