in which we explore attr_writer

Attribute writers are nice, because they can do things other than just assign attributes. If we spelunk some, though, a troll pops up and startles us with unexpected return values. Let’s explore.

into the mines

irb:0> def jumping= q
irb:1>   puts "jumped #{q}"
irb:2>   "jumping is so cool"
irb:3> end
=> nil

If we invoke the method as explicitly as possible, it behaves normally:

irb:4> self.send(:jumping=, "around")
jumped around
=> "jumping is so cool"

If we invoke it via the dot, but without send, the method gets called, but the syntax parser delivers the parameter as the return value. No local variable gets assigned (jumping is still undefined), but the actual return value is lost:

irb:5> self.jumping=("around")
jumped around
=> "around"

If we invoke the method “bare”, the = syntax triggers Ruby’s local variable assignment routine. Our method is never called:

irb:6> jumping=("around")
=> "around"

Watch out for those stalagtites.

activerecord is always relevant

This seems to be why assigning to a field via field= "something" in an ActiveRecord callback doesn’t do anything. It assigns a local variable and never actually calls the accessor method.

@field= "something" doesn’t work either, for a similar reason. Even though you can access fields with instance variables, the accessor methods don’t get called on assignment, so the new value never finds its way back to the hash used to update the database.