How To Modify Default Setters and Getters in Rails Models

by Mike Zazaian at 2009-09-28 02:51:10 UTC in rails syntax

a brief overview on using the read_attribute and write_attribute methods, and their shorthands, for overriding default setter/getter behaviour in Rails

no comments no links ["

Even in quite deliberate past attempts to whittle these articles down to\nsomething much more bloggy and svelt, I've failed sensationally, and almost\nwithout exception ended up spilling two thousand plus words onto a page that\nbegs for few more than half that. I'll try to remedy this although, as must be\npainfully evident, I'm already failing miserably.

\n\n

THAT SAID -- this is going to be the first stab at a series of reasonably quick\n\"bet you didn't know but now you do\"-style how-to articles, which should deliver\nthe kind of wham-bam-thank-you-ma'am attitude that modern web audiences crave,\nand should surely leave you feeling violated and devoid of self-worth.

\n\n

Sound good? Onto it then --

\n\n

modifying getters, or \"how to keep the barking of vicious poodles to a minimum\"

\n\n

Have you ever gotten stuck in an infinite loop in one of your models, by trying\nto alter the behavior of a model attribute inside the method that defines or is\nnamed identically as the attribute itself? Now that you think about it, are you\nsurprised? I hope not, and I hope that the invertiable Picadilly Circus into\nwhich you mercilessly jammed your Rails app was lesson enough for both you and\nit.

\n\n

No, there's nothing inherently wrong with altering or appending to the default\nmethods that Rails provides you with, you just have to do it right.

\n\n

This isn't right:

\n", nil, "
\n
#!/app/models/poodle.rb\n\nclass Poodle < Dog\n  #...some other code here\n\n  def bark\n    if angry?\n      bark + "woof woof woof!"\n    end\n  end\n\nend
\n
\n", nil, "

Did you guess why? Yes, invariably our poor Poodle's bark will continue to add to\nitself until either your server has crashed or the poodle (Craig, we'll call him)\nhas died. Either way it's a messy scenario, and poor Craig (and/or your server\nadministrator) will be deceased from exhaustion.

\n\n

If you're really feeling like a hero today, here's how to save Craig's life:

\n", nil, "
\n
#!/app/models/poodle.rb\n\nclass Poodle < Dog\n  #...some other code here\n\n  def name\n    "Craig"\n  end\n\n  def bark\n    if angry?\n      read_attribute(:bark) + "woof woof woof!"\n    end\n  end\n\nend
\n
\n", nil, "

Now when Craig's REALLY angry he'll bark only 3 extra times rather than 3300 extra times, which should certainly leave you some extra time and energy to stroll ol' Craig down to the park for some lady-hunting (I'm presuming here, of course, that you'd be using Craig to try to ATTRACT women, rather than kill them, as the latter\nwould be both sinister and counter-productive).

\n\n

You might have noticed that there's a flaw in the above code, though, as it assumes that all poodles are named \"Craig\". Well -- in my world they are, and as confounding and terrible as that might seem, this is my hell, and I have no business imposing it upon you.

\n\n

Of course there's an alternative syntax for read_attribute(:bark) that's considered a bit of a shorthand:

\n", nil, "
\n
def bark\n  if angry?\n    self[:bark] + "woof woof woof!"\n  end\nend
\n
\n", nil, "

self, in this instance, referring to the instantiation of this particular\nCraig/Poodle, and [:bark] referring to the bark attribute thereof. This may be a better way to go, too, as I've heard some rumblings that the read_attribute method will soon be depreciated, and that the self[:attribute] syntax will become the Rails\ndefault, but as read_attribute is still defined in the Rails\nAPI under\nActiveRecord::Base, I've no reason to believe that this is true.

\n\n

So that takes care of our getters for accessing and reassigning values to attributes within a model, but what about the setters?

\n\n

modifying setters, or \"how to adjust your code and lifestyle to better accommodate your pets' mental disorders\"

\n\n

Okay, so suppose that you've got two dogs. The other one, fittingly enough, is a rather vain Irish Setter who compulsively wears coloured bandanas, and prefers that you switch up the color every day. So as you're going to be doing a lot of bandana-changing, you'll likely want to write a setter attribute that ensures that you're not giving the dog the same color on two consecutive days (as this infuriates and enrages him).

\n\n

Luckily enough for you, you've got the write_attribute method to help you with the job:

\n", nil, "
\n
#!/app/models/irish_setter.rb\n\nclass IrishSetter < Dog\n\n  def name\n    "Plumbob Wilson"\n  end\n\n  def bandana=(color)\n    unless bandana == color.to_s\n      write_attribute(:bandana, color)\n    else\n      raise BandanaError, "PLUMBOB WILSON WORE THAT COLOR YESTERDAY!!!"\n    end\n  end\nend
\n
\n", nil, "

Granted, this might more elegantly have been executed using a custom validation of some sort, but for the sake of argument, and ensuring beyond a shadow of a doubt that we appease the vicious Plumbob Wilson, our purpose is served.

\n\n

As you might imagine, write_attribute has a shorthand method just as read_attribute does. Voila:

\n", nil, "
\n
def bandana=(color)\n  self[:bandana] = color\nend
\n
\n", nil, "

No, this particular implmentation of the method doesn't change the default behaviour at all, but for our purposes it does the job.

\n\n

Yes, in the phantasmagoric psuedo-reality that is my life, Poodles are named Craig, and Irish Setters have OCD and are named Plumbob Wilson. Hopefully you're beginning to understand the origins of my psychotic ramblings.

\n\n

the tutorial's over, leave now

\n\n

As at the end of Ferris Bueller's Day Off, you can consider this the part of the article where I come out of the shower in a towel, ask you what you're still doing here, and tell you to go home. If you're already at home, then you're fine, but there's really nothing more to read here.

\n\n

Can you believe that I got through this article covering only one topic, and somewhat concisely no less? Neither can I. Originally this article was going to cover three separate topics, thus likely making it at least thrice as long, but I thought the better of it and managed to land somewhere within the vicinity of mankind.

\n\n

Granted, this rambling is really only bloating and distending the article at this point, but you've learned (hopefully) how to modify setters and getters inside of Rails models, and are, by default, a greater humon than you were even two minutes ago. Kudos, Ralph Machio, you're a friggin' genius.

\n"]

no comments

login to post comments, or register to post a comment

latest links

Help.GitHub - Multiple SSH keys The article from github help mirroring this process
ones zeros majors and minors ones zeros majors and minors: esoteric adventures in solipsism, by chris wanstrath
ActiveScaffold A Ruby on Rails plugin for dynamic, AJAX CRUD interfaces

login

register activate reset

feeds

articles/rss

topics

staff

editor

about

doblock focuses on ruby, rails, and all things that can help ruby and/or rails programmers hone their skills.

Techniques, tutorials, news, and even free open-source applications, doblock seeks to fill in the cracks of the ruby/rails blogosphere.

doblock v. 0.10.1 powered by Rails