<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss version="2.0">
  <channel>
    <title>Perspectives: Writings from The Killswitch Collective</title>
    <link>http://www.killswitchcollective.com/blog/index.xml</link>
    <description>Perspectives is the blog of The Killswitch Collective, a Chicago-based web development, design and communication firm.</description>
    <language>en-us</language>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/killswitchcollective/perspectives" type="application/rss+xml" /><item>
      <title>Understanding Your Communication Style</title>
      <category>Perspectives</category>
      <description>&lt;style type="text/css"&gt;
  #communication_style blockquote {
    margin: 10px 0;
    padding: 10px 30px;
    line-height: 1.4;
    border-top: 1px solid #ddd;
    border-bottom: 1px solid #ddd;
  }
#communication_style strong {
  font-weight: bold;
}
#communication_style em {
  font-style: italic;
}
&lt;/style&gt;
&lt;div id="communication_style"&gt;
&lt;p&gt;Developers don't argue.  If disagreements do occasionally occur, the topic is usually settled or dropped in favor of something more productive.  And designers?  These girls have so much work they don't even have the chance to realize that the workplace is a social setting.&lt;/p&gt;

&lt;p&gt;However, this firm is constantly expanding, and even a few tiffs may eventually snowball into arguments of unnecessarily enormous proportions.  With this said, Ben had the excellent foresight to offer me a chance at educating myself on diffusing difficult situations in the workplace.  I found the seminar (Dealing with Difficult People, sponsored by CareerTrack) so enlightening, I'd like to share with everyone some tidbits I have learned.&lt;/p&gt;

&lt;p&gt;Approximately 75% of long term job success stems directly from people skills; only 25% derives from technical knowledge.  This is huge!  So what can you do to ensure successful people skills?&lt;/p&gt;

&lt;h3&gt;Listen&lt;/h3&gt;
&lt;p&gt;This is an incredibly simple act, and yet few people take the time to actually stop what they are doing, direct all their attention onto others, and really listen.  In order to do this, you need 3 things: the capacity to listen (focus), the desire (or willingness) to listen, and the ability to evaluate what you hear.  In other words, you need to WANT to grasp what it is others are saying to you, and go out of your way to do so.  People really only want 2 things out of their transactions with others, and that is to be valued and understood.  You can show both of these by hearing them out to completion, and then going over what you heard in your own words.  A good example of a listener at KSC, and I think the devs will back me up on this one, is Neal; when someone has a question, no matter how minute, he will take out both headphones, turn his chair towards you and give you ALL of his attention.  This indirectly lets people know that they matter and creates feelings of appreciation and respect among employees.&lt;/p&gt;

&lt;h3&gt;Body Language&lt;/h3&gt;
&lt;p&gt;Interestingly, body language (55% of communication) and tone of voice (38% of communication) affect how people react to you much more than what you actually say (only 7% of communication).  The best way to communicate, is to follow the anagram SOFTEN:&lt;/p&gt;

&lt;blockquote&gt;
&lt;strong&gt;S&lt;/strong&gt;mile&lt;br /&gt;
&lt;strong&gt;O&lt;/strong&gt;pen Stance&lt;br /&gt;
&lt;strong&gt;F&lt;/strong&gt;orward lean&lt;br /&gt;
&lt;strong&gt;T&lt;/strong&gt;erritory&lt;br /&gt;
&lt;strong&gt;E&lt;/strong&gt;ye contact&lt;br /&gt;
&lt;strong&gt;N&lt;/strong&gt;od head
&lt;/blockquote&gt;

&lt;p&gt;The quickest way to anger someone is to fold your arms, look past him, and lean back in your chair as soon as he walks into your office.  The best way to diffuse anger is by modeling behavior you would like others to exhibit.  Nothing crossed implies honesty and openness, leaning forward demonstrates interest, and maintaining eye contact builds trust.  Speaking softly and slowly, and avoiding personal space and pointing are also good ways to communicate effectively.  To learn more, you can visit &lt;a href="www.changingminds.org/techniques/body/bodylanguage.htm"&gt;www.changingminds.org/techniques/body/bodylanguage.htm&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Don't Be Scared!&lt;/h3&gt;
&lt;p&gt;The best way to handle interactions with people is to do so assertively.  If you aren't sure what being assertive entails, keep in mind this basic message: "This is what I think.  This is what I feel.  This is how I see the situation."  It respectfully brings the issue out on the table to be dealt with quickly and with everyone's side of the situation in mind.  You can't possibly solve a problem if you aren't even sure what it is!   And don't back down!  The more you stick to your guns, the more respect you'll get, I promise.  If you want a situation to change, you really have to confront it immediately and persistently (as scary as that sounds).  A good way to assert yourself with others is by following this sentence pattern:&lt;/p&gt;

&lt;blockquote&gt;
"For the sake of (name the relationship), when you (name the problem) and this happens (what happens when the problem occurs), I feel (name honest feelings).  What I want is (name what you would rather happen).  Can we agree?"
&lt;/blockquote&gt;

&lt;p&gt;What you are looking to do is change the behavior, not the person.  It will never help to attack the person who is causing problems, but behaviors can be modified easily.  It is also important to add "Can we agree?" at the end of the sentence; you are then in oral contract with the person, and can bring this up if he engages in problematic behavior again.  Here's a more detailed example:&lt;/p&gt;

&lt;blockquote&gt;"For the sake of our friendship as neighbors, when you let your dog poop all over my yard and then I accidentally roll in it when I play with my kids, I get extremely irritated.  What I want is for you to pick up the poop immediately after you let the dog out.  Can we agree?"&lt;/blockquote&gt;

&lt;p&gt;Remember, it takes at least 6 tries and 21 days to form a new habit, so be patient with those "lazy neighbors."&lt;/p&gt;

&lt;p&gt;The most interesting part of the seminar was hearing about CareerTrack's version of the 4 different personality types: thinkers, relaters, directors and socializers.  For reference, these would be found in the Myers-Briggs personality test as Introvert Thinker, Introvert Feeler, Extrovert Thinker and Extrovert Feeler, respectively.&lt;/p&gt;

&lt;p&gt;Curious as to where you fit in??  Here's a little test you can take to get an idea:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www2.killswitchcollective.com/articles/personality_types/diff-people-1.gif"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www2.killswitchcollective.com/articles/personality_types/diff-people-2.gif"&gt;&lt;/p&gt;

&lt;h3&gt;Thinkers&lt;/h3&gt; 
&lt;p&gt;These guys are the meticulous task-oriented individuals of the world.  Organized, focused and on-point, thinkers need things to be correct more than anything.  In fact, their main goal in the workplace is ACCURACY.  Because they can be perfectionists, thinkers are not very good at receiving constructive criticism, and may complain if they have a problem they can't seem to fix.  The best way to work with them is to provide them with as much information as you can, the "who, what, where, why, and how" of the situation, so that they can see and understand your process.  Also, help them move into "problem-solving mode" by directing their concerns toward working on a solution.  Negativity may rear its ugly head when things go wrong, and the best way to counteract it is to bring the thinker back to the task at hand: instead of what CAN'T be done, focus on what CAN.&lt;/p&gt;

&lt;h3&gt;Relaters&lt;/h3&gt;
&lt;p&gt;Can't we all just get along??  This is the relaters' motto; their goal is STABILITY and harmony within their relationships.  Sensitivity and a need to be liked drives their actions, and they tend to shut down, submit, and exhibit passive aggressive behavior when pressured.  When speaking with relaters, be casual and sincere, slow down and listen to how they feel about the issue, make honesty safe by being open and patient to what they have to say, and reinforce to them the fact that you want to get along with them, and that the relationship is important to you.  All of these things will help create a safe haven for confidence and honest transactions, and will prevent the break-downs in communication which lead to arguments.&lt;/p&gt;

&lt;h3&gt;Directors&lt;/h3&gt;
&lt;p&gt;Also known as people who "get it done," directors seek to be in CONTROL, and always know what they want and how to get it.  Life is a giant comprehensive checklist, and great pains are taken to remain focused, direct and blunt on each task and with each individual they come into contact.   Trust and respect are very important, and at times, if you don't gain either, you may become invisible.  They tend to react aggressively to pressure:  they may raise their voices, bully others and become irritable and impatient.  When working with them, try to be proactive, task-oriented, and direct in your speech.  Also, don't be afraid to stand your ground!  They respect those who command it.  Show them that you understand and support their goals, and they will become more flexible with your ideas.&lt;/p&gt;

&lt;h3&gt;Socializers&lt;/h3&gt;
&lt;p&gt;This one is my favorite.  Socializers are direct, charismatic, energetic, creative, people-oriented and adore RECOGNITION.  On the flip-side, they are disorganized, sensitive, dramatic, horrible procrastinators and cannot function without recognition.  When asking them to do something, focus more on the results rather than the process; they enjoy creative freedom when working on projects.  Show flexibility and positive affirmation when talking to them, and don't forget to let them talk as well; this will help them feel valued, allowing them to open up to criticism and suggestions and utilize their enthusiasm and optimism to the max.&lt;/p&gt;

&lt;p&gt;Of course, not everyone will fit neatly into one specific category, but you can definitely use these descriptions to better understand yourself and how to communicate with fellow coworkers effectively.&lt;/p&gt;
&lt;/div&gt;</description>
      <pubDate>Wed, 16 Jul 2008 14:15:55 -0700</pubDate>
      <link>http://www.killswitchcollective.com/articles/28</link>
      <guid>http://www.killswitchcollective.com/articles/28</guid>
    </item>
    <item>
      <title>Exercises in Pruning Code, Episode Two</title>
      <category>Development</category>
      <description>


 &lt;style&gt;
  .highlight  { background: #f8f8f8; }
.highlight .c { color: #408080; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #808080 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #7D9029 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #A0A000 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
 &lt;/style&gt;





&lt;style&gt;
  .highlight {
    background-color: #EEE;
    padding: 2px;
    border: 1px dotted #CCC;
  }
  .label {
    padding: 0;
    margin: 0;
    text-align: right;
    font-style: italic;
  }
&lt;/style&gt;

&lt;h3&gt;A story about building an application&lt;/h3&gt;
 
&lt;p&gt;
 I was recently working on a Ruby on Rails application that had a section for 
 sending messages. This sounds pretty easy, right?  I started with a 
 &lt;code&gt;User&lt;/code&gt; model and a &lt;code&gt;Message&lt;/code&gt; model and some basic
 associations:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:messages&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;  
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.1 - initial &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Message&lt;/code&gt; models&lt;/p&gt;
&lt;p&gt;
 But when it came time to actually start building the application, I found this simple model code was not
 enough.  The devil is in the details, as they say. There was a lot of functionality
 I needed to add beyond just a list of messages connected to a &lt;code&gt;User&lt;/code&gt;.
&lt;/p&gt;

&lt;h4&gt;1) Filtered views&lt;/h4&gt;
&lt;p&gt;I needed different views of the messages such as sent messages, drafts, and deleted messages.&lt;/p&gt;

&lt;p&gt;How do I determine 'draft' status?  Well one way is to fill in a &lt;code&gt;delivered_at&lt;/code&gt; date
whenever a message is sent. Then a draft is just a &lt;code&gt;Message&lt;/code&gt;
with no &lt;code&gt;delivered_at&lt;/code&gt; date.  
&lt;/p&gt;

&lt;p&gt;So after adding that field (and a &lt;code&gt;sender_id&lt;/code&gt; and &lt;code&gt;receiver_id&lt;/code&gt;) to the database 
I went to my &lt;code&gt;messages_controller.rb&lt;/code&gt; file and added a few methods that looked sort of like this:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and recipient_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt; 
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is NULL and sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.2 - initial fragment from &lt;code&gt;messages_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;2) Pagination&lt;/h4&gt;

&lt;p&gt;Nobody wants to load a page of 1000 messages at a time, so I needed to be able to break up that list into limited
 sized chunks.
 I used the excellent plugin &lt;code&gt;&lt;a href="http://github.com/mislav/will_paginate/tree/master"&gt;will_paginate&lt;/a&gt;&lt;/code&gt; 
 for that purpose.  Then my controllers methods got a little more verbose:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and recipient_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt; 
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is NULL and sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.3 - fragment from &lt;code&gt;messages_controller.rb&lt;/code&gt; with pagination&lt;/p&gt;

&lt;h4&gt;3) The ability to flag content (i.e. spam, objectionable content etc...)&lt;/h4&gt;

&lt;p&gt;What if someone gets spam in the message system - or something objectionable in some other way.  Well I need
  to filter that stuff out.  I added a &lt;code&gt;Flag&lt;/code&gt; model and connected that to messages like so:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.4 - &lt;code&gt;Message&lt;/code&gt; model with flags added&lt;/p&gt;


&lt;p&gt;However, at this point my controller methods are starting to look like this:&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and &lt;/span&gt;
&lt;span class="s1"&gt;         flags.flagged_item_id is NULL and &lt;/span&gt;
&lt;span class="s1"&gt;         recipient_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and &lt;/span&gt;
&lt;span class="s1"&gt;         flags.flagged_item_id is NULL and &lt;/span&gt;
&lt;span class="s1"&gt;         sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt; 
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is NULL and&lt;/span&gt;
&lt;span class="s1"&gt;         flags.flagged_item_id is NULL and &lt;/span&gt;
&lt;span class="s1"&gt;         sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.5 - fragment from &lt;code&gt;messages_controller.rb&lt;/code&gt; with flags&lt;/p&gt;

&lt;p&gt;I'm looking at some ugly code - with a lot of repetition.  How do I pare this down?&lt;/p&gt;

&lt;h4&gt;Begin Pruning&lt;/h4&gt;

&lt;p&gt;My first thought is that if anything in my application can be flagged, I should
 be able to do a little meta-programming to create a find method that will give me only
 un-flagged items.  Ideally I could even send in all the rest of the find arguments exactly the same.
&lt;/p&gt;

&lt;p&gt;
 There is the 
&lt;code&gt;&lt;a href="http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality"&gt;named_scope&lt;/a&gt;&lt;/code&gt; 
 addition to Rails 2.x that does just that - but I also want
 something I can add to any class as a &lt;code&gt;Mixin&lt;/code&gt;.  That way I can write code like this:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;SomeOtherThing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.6 - call to imagined method &lt;code&gt;unflagged_items&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The method 
&lt;code&gt;&lt;a href="http://railscasts.com/episodes/5"&gt;with_scope&lt;/a&gt;&lt;/code&gt; is a good candidate for sending in 
some pre-determined find conditions - but leaving it open to add more later.  I'm  wanting to 
add the following method to all my classes that need to be flagged:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;with_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:find&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;flags.flagged_item_id is NULL&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;  
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.7 - code for imaginary &lt;code&gt;unflagged_items&lt;/code&gt; method&lt;/p&gt;

&lt;p&gt;How do I do that? Well, I can turn that code into a Module and add it to any class 
automatically using a little metaprogramming:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Flaggable&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;included&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:flagged_item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:dependent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:destroy&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;with_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:find&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;flags.flagged_item_id is NULL&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:flags&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;  
          &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;  
      &lt;span class="k"&gt;end&lt;/span&gt;  
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.8 - &lt;code&gt;Flaggable&lt;/code&gt; module&lt;/p&gt;

&lt;p&gt;Any model I put the line &lt;code&gt;include Flaggable&lt;/code&gt; in will have that method available.  
So if I include it in the &lt;code&gt;User&lt;/code&gt; class I've added a method
&lt;code&gt;user.messages.unflagged_items&lt;/code&gt; which returns a sort of incomplete version of the find function - with all
the necessary logic to limit the list to unflagged items already filled in.  I still have to fill in the &lt;code&gt;:all&lt;/code&gt;
or &lt;code&gt;:first&lt;/code&gt; or any other &lt;code&gt;:conditions&lt;/code&gt; I want.  But the function is sort of half-called.
This is a useful thing - getting half-called functions.  In functional programming it's called currying.  I'll come
back to that in a moment.
&lt;/p&gt;

&lt;p&gt;
Anyway, So now my controller methods now look like this:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and recipient_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
    &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is not NULL and sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt; 
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;delivered_at is NULL and sender_id = ?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.9 - fragment from new &lt;code&gt;messages_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;Continue Pruning&lt;/h4&gt;
&lt;p&gt;
 It's getting better, but isn't there some way I can pare it down even more?  Now I'll go to the 
&lt;code&gt;User&lt;/code&gt; model. Instead of simply using &lt;code&gt;has_many :messages&lt;/code&gt; - since 
&lt;code&gt;has_many&lt;/code&gt; 
supports blocks - I can add some more convenience methods to the &lt;code&gt;User&lt;/code&gt; class:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;

    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:received_messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:foreign_key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;recipient_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="ss"&gt;:class_name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Message&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delivered_and_unflagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;delivered_at IS NOT NULL&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@messages_per_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:sent_messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:foreign_key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sender_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="ss"&gt;:class_name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Message&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delivered_and_unflagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;unflagged_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;delivered_at IS NOT NULL&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@messages_per_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:draft_messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:foreign_key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sender_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="ss"&gt;:class_name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;delivered_at IS NULL&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;paginated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@messages_per_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;received_messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivered_and_unflagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivered_and_unflagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draft_messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.10 - more developed &lt;code&gt;User&lt;/code&gt; model&lt;/p&gt;

&lt;p&gt;I'm doing pretty well with reduction of code in my controller now.  The only ugly bit of code leftover
 is the &lt;code&gt;params[:page]...&lt;/code&gt; bit - but I can make that slightly better too by factoring it out.  
 I would like to use &lt;code&gt;params[:page] || 1&lt;/code&gt; but &lt;code&gt;params[:page]&lt;/code&gt; returns an empty
 string if there is no matching parameter and &lt;code&gt;will_paginate&lt;/code&gt; interprets an empty string
 as a request for page 0 and returns an error.  So I have to use the longer statement with the ternary operator.
 Now my controller code looks like this:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt; 
   &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drafts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;figure_page&lt;/span&gt;
   &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.11 - pruned fragment from &lt;code&gt;messages_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I'm happy enough with that.  I've made different lists of messages
for the currently logged on &lt;code&gt;User&lt;/code&gt; that automatically paginate and filter out flagged items 
with just one line of code per method.
&lt;/p&gt;

&lt;h4&gt;3) Next and Previous Message&lt;/h4&gt;

&lt;p&gt;I'm not done yet though - because the view page of a message needs a &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;previous&lt;/code&gt; link.
So if the user is looking at a draft - &lt;code&gt;next&lt;/code&gt; should be the next draft - not the next sent message - and previous
should be the previous draft - not the previous sent message. Make sense?
&lt;/p&gt;

&lt;p&gt;One way I could do this
is to have a &lt;code&gt;show_draft&lt;/code&gt; method, a &lt;code&gt;show_sent_item&lt;/code&gt; method etc... and just call the correct 
link from the correct listing page (i.e. the list of all drafts page has links to &lt;code&gt;show_draft&lt;/code&gt;, 
the sent items page has links to &lt;code&gt;show_sent_item&lt;/code&gt; etc...).
&lt;/p&gt;

&lt;p&gt;There are 2 problems with this though.  1) That is creating several methods for basically one 'show' action.  So they
will all be virtually the same code over and over again. 2) I'm using a partial to render the list of messages - so 
I'd have to send in some way to create a different link based on the type of filter ('drafts', 'sent mail' etc...)
but I'd rather just call &lt;code&gt;render :partial =&gt; "message", :collection =&gt; @messages&lt;/code&gt;.  
I don't want the partial to have to worry about what particular filtered list of messages it happens to
be rendering.
&lt;/p&gt;

&lt;p&gt;I'm sure there are a lot of ways to solve this. What I came up with was to add a 'from' value as a 
parameter for each &lt;code&gt;link_to :action =&gt; 'show'&lt;/code&gt;
in the partial. That way I could just append 
&lt;code&gt;params[:action]&lt;/code&gt; to every url and by the time the controller gets the request, it knows where the 
request is coming from.  This gives me the information I need to respond differently to the &lt;code&gt;show&lt;/code&gt;
action depending on that parameter.  And leaves that logic out of the view.
&lt;/p&gt;

&lt;p&gt;In order to get the next and previous messages though, 
I needed to be able to identify and generate a list of messages based on the value of 
a string (i.e. value of &lt;code&gt;params[:from]&lt;/code&gt;).
&lt;/p&gt; 

&lt;p&gt;The code I wrote at first looked something like this and was in the controller:&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="vi"&gt;@message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# need @messages for previous, next&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:from&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sent_mail&amp;#39;&lt;/span&gt;
      &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;drafts&amp;#39;&lt;/span&gt;
      &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drafts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;#...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bulk_action&lt;/span&gt;
    &lt;span class="c1"&gt;# ... do bulk action&lt;/span&gt;

    &lt;span class="c1"&gt;# need @messages for previous, next&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:from&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sent_mail&amp;#39;&lt;/span&gt;
      &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;drafts&amp;#39;&lt;/span&gt;
      &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drafts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;#...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.12 - fragment of &lt;code&gt;messages_controller.rb&lt;/code&gt; with new code&lt;/p&gt;

&lt;p&gt;So I've lost some of my simplicity, I'm repeating myself again and my code is in need of pruning.&lt;/p&gt;

&lt;p&gt;What I need is a function that returns a function waiting to receive arguments.  This is similar to the &lt;code&gt;with_scope&lt;/code&gt;
method I mentioned earlier, and the idea of function currying. I need a function that's partially filled out - but not called yet - waiting for 
some parameters.  This is a good place
to use the the fact that a &lt;code&gt;Method&lt;/code&gt; is just another object in Ruby - and create a method to 
return whichever &lt;code&gt;User&lt;/code&gt; method I want.
&lt;/p&gt;

&lt;h4&gt;A method that returns a method&lt;/h4&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# special case of &amp;#39;index&amp;#39; action&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;
       &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inbox&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
       &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.13 - fragment from &lt;code&gt;User&lt;/code&gt; model&lt;/p&gt;

&lt;p&gt;returns a method as an object waiting for arguments. So I can put that
code in my &lt;code&gt;User&lt;/code&gt; class and I can call it like this in my controller:
&lt;/p&gt;


  
  &lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
  &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 
 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drafts&lt;/span&gt; 
  &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
  &lt;span class="vi"&gt;@message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:from&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.14 - fragment from new &lt;code&gt;messages_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;One last trick&lt;/h4&gt;

&lt;p&gt;I'm almost done.  But I can go one step further in minimization of code.  Taking
advantages of the fact that a &lt;code&gt;method&lt;/code&gt; can be converted to a block by putting an &lt;code&gt;&amp;amp;&lt;/code&gt;
in front of it. In the controller, since all the returned methods are taking that same &lt;code&gt;figure_page&lt;/code&gt;
parameter - I can factor that out as a method accepting a block and do something like this:&lt;/p&gt;



  
  &lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:inbox&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sent_mail&lt;/span&gt;
    &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:sent_mail&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="vi"&gt;@message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_messages_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:from&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;figure_page&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p class="label"&gt;Fig.15 - fragment from another revision to &lt;code&gt;messages_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It's odd looking, I admit. I've lost a little readability for the sake of density.  
But I've left myself very little code in the controller
and nothing specific about controllers in the model.  That much I like.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;So if you ever writing a Ruby on Rails application that has messages that need to be filtered, paginated and 
include a detail view with a 
previous, next link - you might be able to glean some code from the article to help get 
started.  Also, today's lesson is that it's sometimes handy to pass around functions as objects. 
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; I've included a &lt;a href="http://www2.killswitchcollective.com/articles/blog_ksc_ep2.zip"&gt;zip&lt;/a&gt; 
file of various items related to this article.  It includes
some Ruby code as a demonstration which requires a sqlite3 installation.
Also, I used Python to generate this document with all the color-coded sections. 
I've included that in case it is of interest
to anyone.  It requires the &lt;code&gt;Mako&lt;/code&gt; and &lt;code&gt;Pygments&lt;/code&gt; packages. 
&lt;/p&gt;



</description>
      <pubDate>Wed, 09 Jul 2008 07:00:37 -0700</pubDate>
      <link>http://www.killswitchcollective.com/articles/27</link>
      <guid>http://www.killswitchcollective.com/articles/27</guid>
    </item>
    <item>
      <title>A Fresh Look at Virtualization</title>
      <category>Research</category>
      <description>&lt;p&gt;For a few years I have been experimenting with virtualization software and technology. Virtualization is not new, and chances are that some of the programs you use on a daily basis using simulation. Manufacturers want to pack as many features as possible into their products and virtualization allows them to create more attractive offerings to purchasers.&lt;/p&gt; 

&lt;p&gt;It has been only recently, however, that virtualization has caught the public eye as software has evolved to the level where entire operating systems can now be virtualized. Thanks to virtualization Macs can now run Windows, PC's can run Linux and a single computer can run several systems simultaneously. For Killswitch, virtualization means the ability to assess our development solutions in different computing environments without incurring the overhead of purchasing new machines.&lt;/p&gt;

&lt;h3&gt;Pros and Cons of Virtualization&lt;/h3&gt;

&lt;p&gt;Here are some possible benefits of integrating virtualization into your workflow:&lt;/p&gt;
&lt;ol style="list-style: decimal; padding-left: 30px;"&gt;
&lt;li&gt;It allows businesses and power users to test and assess solutions in different environments and configurations on a single machine.&lt;/li&gt;

&lt;li&gt;It gives businesses the ability to test out a new system without having to purchase dedicated hardware for it.&lt;/li&gt;

&lt;li&gt;It gives power users and businesses the flexibility to switch between different operational environments (for example, between desktop work and local server environments).  &lt;/li&gt;     
             
&lt;li&gt;It saves money because a system can run on pre-existing hardware.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There can, however, be certain drawbacks:&lt;/p&gt;
&lt;ol style="list-style: decimal; padding-left: 30px;"&gt;
&lt;li&gt;Older hardware may not have the processing power to successfully run the native system, virtualization and the guest system.&lt;/li&gt;

&lt;li&gt;Some functions and features may not work correctly if there are system incompatibilities with the hardware.&lt;/li&gt;

&lt;li&gt;Memory limitations may prohibit the environment you are trying to test from properly installing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Overcoming Obstacles&lt;/h3&gt;

&lt;p&gt;In my opinion, the biggest obstacles to widespread virtualization are memory limitations and company end user policies. We are barely breaking out of the 4 GB memory limitation that has plagued the computing world for the past several years. Finally there are motherboards that allow users to upgrade from the 4 gigabyte limit to 8 or 16 GB, provided you use the right processor and operating system. The more memory available on a system, the better a computer running virtual systems can handle errors and bottlenecks.&lt;/p&gt;            

&lt;p&gt;The other problem, which is progressively getting more annoying, is a company's &lt;acronym title="End User License Agreement"&gt;EULA&lt;/acronym&gt;. I understand a company's need to protect its profit margin, but that should not come at the cost of consumer satisfaction. Allowing virtualization of a product does not take away from it; in fact, if the product in question is stable and user friendly, that product will fly off the shelves!&lt;/p&gt;

&lt;p&gt;Let's say that your computer is running Ubuntu, but a piece of software you need is available for Windows only, there simply is no equivalent for the Ubuntu platform. What's a user to do? Obviously, you could go out, spend a lot of money and buy a new Windows machine to that one program. Thanks to virtualization, however, you can now load a copy of Parallels Linux on your machine and install Windows XP or Vista. &lt;em&gt;Note: Virtualizing Vista Business and Ultimate violates the software's &lt;acronym title="End User License Agreement"&gt;EULA&lt;/acronym&gt;. If anything goes wrong, you are on your own.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here at Killswitch we primarily use Macintosh computers, so virtualizing Windows XP has come in handy. At one point we had a client who misplaced some Flash source files that were used to create a .swf file on their site. Wanting to change the content in this .swf file, we needed a SWF decompiler (and we needed it fast). Though we were concerned when we found out the program we needed was Windows only, we were quickly relieved as it ran perfectly on our Macs using Parallels.&lt;/p&gt;           

&lt;p&gt;Based on my personal experience, here are some software virtualization solutions that I would recommend:&lt;/p&gt;

&lt;h3&gt;Mac Software&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://parallels.com"&gt;Parallels&lt;/a&gt;: This is one of the premiere software packages that you can use to emulate another computing environment. The interface is clear and everything is well explained. I use this both in the office and personally at home.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://store.vmware.com/servlet/ControllerServlet;jsessionid=B93F04C7C046577C4352825FC3C63C32?Action=DisplayPage&amp;Locale=en_US&amp;SiteID=vmware&amp;id=ProductDetailsPage&amp;productID=82532200"&gt;VMware&lt;/a&gt;: I have used VMware and it is right up there with Parallels. Some of the more advanced functions are a little complicated, but there are several tutorials online that can help clear up confusion.&lt;/p&gt;

&lt;h3&gt;Windows Software&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=04D26402-3199-48A3-AFA2-2DC0B40A73B6&amp;displaylang=en"&gt;Virtual PC&lt;/a&gt;: This software is a veteran commercial product and is a leading virtualization program for PCs with a robust feature set.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.virtualbox.org/"&gt;Virtual Box&lt;/a&gt;: This program is free and very straight forward. You can load Windows, Linux and other operating systems, as well as server environments.&lt;/p&gt;</description>
      <pubDate>Mon, 30 Jun 2008 12:20:41 -0700</pubDate>
      <link>http://www.killswitchcollective.com/articles/25</link>
      <guid>http://www.killswitchcollective.com/articles/25</guid>
    </item>
    <item>
      <title>Looking Back at RailsConf 2008</title>
      <category>Development</category>
      <description>&lt;p&gt;Let's face it, everything seems to move at a breakneck pace in our industry. It seems like every other day there is a new start-up with some amazing product that's supposed to change the way all of us work. At least once a week I get software update notifications for some application or another. It is our job (and usually our passion) as developers to keep up with the tools that we use, and constantly be evaluating these upgrades, new features or sometimes even the alternatives. As a Ruby on Rails shop, there is nowhere better to check the pulse of the Rails community than RailsConf 2008.&lt;/p&gt;

&lt;p&gt;RailsConf 2008 was held in Portland, Oregon again this year and Chris and myself had the chance to experience it first hand. It was the first RailsConf for both of us so our expectations were high, and for the most part we weren't disappointed. We met some really cool people from all over the world (including the cool guys from &lt;a href="http://blueboxgrp.com"&gt;Blue Box Group&lt;/a&gt;), picked up a ton of information on where things with the Rails community are headed, and Chris even held a Birds of a Feather (BOF) discussion about his &lt;a href="http://killswitchcollective.com/articles/22"&gt;GiftWrap plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There's simply too much to cover in a single blog post for those who couldn't make it, so please excuse my brevity. You can check out &lt;a href="http://en.oreilly.com/rails2008/public/content/home"&gt;O'Reilly's website&lt;/a&gt; to read all about the events and schedules, and you can even grab most of the presentation materials there too.&lt;/p&gt; 

&lt;p&gt;Maybe my surprise was simply because this was my first RailsConf, but some of the best stuff for me wasn't specifically related to Rails! I went to a cool BOF on Rails alternatives, an interesting discussion about frameworks like Merb, Rack, and Mack, and we even got into the DataMapper ORM and replacing Subversion with Git. I also saw some great presentations on meta-programming, the internal workings of Git, and perhaps the topic I was most curious about – Phusion Passenger. I also enjoyed the well-delivered keynotes from Joel Spolsky and DHH. All these things gave me a taste for what else is out there, and how people are using not only Rails but other tools as well in our industry. The BOF sessions were great as well, bringing small groups of really bright people together to just chat about different topics. Oh, and the food rocked – plus all the Starbucks coffee you can handle, sweet.&lt;/p&gt;

&lt;p&gt;That said, there were a few things that weren't so great that I thought I should share as well. The topic of scalability has been a hot one since way back when. Maybe it's just because we've built several high-traffic applications, but the scalability issue has been beaten to death in my opinion, and was beaten quite a bit more this year with about 5 talks covering scalability. Also, the tutorials weren't really worth the extra fees in my opinion – don't get me wrong, they were useful and interesting, but several of the topics ended up being covered in other sessions that were part of the conference, some of them were even the exact same presentation! Finally, while it was great to get a feel for a lot of the other tools out there being used, I must admit I was hoping for a bit more Rails-specific content. It was great to see the keynote by Jeremy Kemper announcing Rails 2.1 (some great stuff in there), but I still don't have a feel for the roadmap of development for Rails and where things are going next.&lt;/p&gt;

&lt;p&gt;Overall RailsConf was great, and Portland was a great location for it (despite the 4+ hour flight from Chicago). Would I recommend it? Absolutely. You won't find a collection of brighter developers out there than the ones in the Rails community. Everyone seems to 'get it' and they're all interested in advancing the framework and expanding Rails into the main stream. So thanks to everyone who presented, it was quite an experience – see you next year!&lt;/p&gt;</description>
      <pubDate>Fri, 20 Jun 2008 08:00:16 -0700</pubDate>
      <link>http://www.killswitchcollective.com/articles/24</link>
      <guid>http://www.killswitchcollective.com/articles/24</guid>
    </item>
    <item>
      <title>Letting Google Globalize Your Rails App</title>
      <category>Development</category>
      <description>&lt;style&gt;
pre {
margin-bottom: 10px;
}
&lt;/style&gt;
&lt;p&gt;&lt;a href="http://www2.killswitchcollective.com/articles/globalize_with_google.zip"&gt;Just give me the globalize_with_google plugin now!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Anybody who's looked into localizing or internationalizing a Rails app has probably come across the "Globalize" plugin.  It's a bit of an 800 lb. gorilla in the sense that it supports potentially hundreds of languages, automatic generation of validation messages, and even multiple pluralization cases based on the exact number of objects being counted.  (There's a story about a people whose language only had three numbers- 1, 2, and 'many'.  Globalize can handle that!)  But as long as installation is as easy as "script/plugin install ...", who cares how much the gorilla weighs?&lt;/p&gt;

&lt;p&gt;On a related note, Google recently released a series of &lt;a href"http://code.google.com/apis/ajax/"&gt;AJAX APIs&lt;/a&gt; that are dead-simple to plug in to any web app, including one that does &lt;a href="http://code.google.com/apis/ajaxlanguage/"&gt;automatic translation&lt;/a&gt;.  Can you guess where I'm going with this?  &lt;/p&gt;

&lt;p&gt;As soon as I saw Google's announcement that they were offering a free translation API, I started thinking about how to write a plugin that used it to initialize a Globalize database.&lt;/p&gt;

&lt;p&gt;My solution, as sketched on the back of a napkin, had two pieces: The first would override Globalize's "String.translate" method. The other one would cache the translations so we still had a checklist of phrases for professional translators to go over, if necessary, and so we weren't dependent on the uptime of Google's servers for the functionality of our application.  (Not that Google has lousy uptime; but if by chance they ever take down the service or start charging for translations, we can't have our translations just &lt;em&gt;turn off&lt;/em&gt;).&lt;/p&gt;

&lt;h3&gt;The Actual Translation&lt;/h3&gt;
&lt;p&gt;This part was the easiest.  We just modify Globalize's ".t" method to use Google's translation service:&lt;/p&gt;

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#CC7833"&gt;module &lt;/span&gt;&lt;span class="module"&gt;String&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.included&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:alias_method_chain&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:translate&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:google&lt;/span&gt;
    &lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:alias_method&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:t&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:translate&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;translate_with_google&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;default&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span style="color:#DA4939"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;arg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span style="color:#DA4939"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;local_base_language&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span style="color:#CC7833"&gt;defined?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span style="color:#DA4939"&gt;BASE_LANGUAGE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span style="color:#DA4939"&gt;BASE_LANGUAGE&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;en&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

    &lt;span style="color:#BC9458"&gt;#don't translate this if it's already written in the target language&lt;/span&gt;
    &lt;span style="color:#CC7833"&gt;return&lt;/span&gt; &lt;span style="color:#DA4939"&gt;self&lt;/span&gt; &lt;span style="color:#CC7833"&gt;if&lt;/span&gt; &lt;span style="color:#DA4939"&gt;Locale&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;language&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iso_639_1&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;local_base_language&lt;/span&gt;

    &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span style="color:#DA4939"&gt;Locale&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;translate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span style="color:#DA4939"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;__translate__&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;arg&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span style="color:#CC7833"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span style="color:#CC7833"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt;  &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;__translate__&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; 

    &lt;span style="color:#CC7833"&gt;return&lt;/span&gt; &lt;span class="punct"&gt;%Q{&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;span id=&amp;quot;translation_&lt;span class="expr"&gt;#{self.object_id}&lt;/span&gt;&amp;quot;&amp;gt;&lt;span class="expr"&gt;#{self}&lt;/span&gt;&amp;lt;/span&amp;gt;
                &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt; 
                ......&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
    &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;The only flaw is that you can't use this on the labels of buttons or in javascript alert()s.  Instead of showing a translated string, it would display a huge mess of javascript.  I don't think there's a simple workaround for this, though, since the ".t" method can't know what context it is being called in.  So in your views, make sure all of your translated buttons use something like &lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="ident"&gt;input&lt;/span&gt; &lt;span class="ident"&gt;type&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;submit&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;%= &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Submit&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;.translate_without_google %&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;h3&gt;The Caching&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;&lt;em&gt;This&lt;/em&gt;&lt;/b&gt; part nearly killed me.  How do you cache the result of a google translation?  It never goes through our server!  The solution was a little convoluted, but &lt;em&gt;very&lt;/em&gt; educational to a guy who had never written a plugin before.&lt;/p&gt;

&lt;p&gt;First, we need to make the Javascript report the result of each translation back to our server.  Fortunately, Google's "translate" function offers a callback once the translation is complete.  So I just told it to execute the following:&lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span style="color:#DA4939"&gt;Ajax&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Request&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span style="color:#A5C261"&gt;/cache_google_translation&lt;/span&gt;&lt;span class="punct"&gt;',{&lt;/span&gt;&lt;span class="ident"&gt;method&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;parameters&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;phrase=&lt;span class="expr"&gt;#{self}&lt;/span&gt;&amp;amp;translation=&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;+&lt;/span&gt;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;translation&lt;/span&gt;&lt;span class="punct"&gt;});&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Next, we need a way for our Rails app to recognize the request for caching.  But how can a plugin respond to a request like a controller does?  It takes two steps. First you need to make a pseudo-controller that will do the caching:&lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#CC7833"&gt;class &lt;/span&gt;&lt;span class="class"&gt;TricksController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#DA4939"&gt;ActionController&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Base&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;cache_google_translation&lt;/span&gt;
    &lt;span class="ident"&gt;bound_vars&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span style="color:#6E9CBE"&gt;:translation&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span style="color:#6E9CBE"&gt;:phrase&lt;/span&gt;&lt;span class="punct"&gt;]]&lt;/span&gt;
    &lt;span style="color:#DA4939"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connection&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;execute&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;UPDATE globalize_translations SET built_in = 2, text = ? WHERE tr_key = ? AND language_id = &lt;span class="expr"&gt;#{Locale.language.id}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="ident"&gt;gsub&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span style="color:#A5C261"&gt;?&lt;/span&gt;&lt;span class="punct"&gt;'){&lt;/span&gt;&lt;span style="color:#DA4939"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connection&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;quote&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;bound_vars&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shift&lt;/span&gt;&lt;span class="punct"&gt;)})&lt;/span&gt;
    &lt;span style="color:#DA4939"&gt;Locale&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;translator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;put_in_cache&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span style="color:#6E9CBE"&gt;:phrase&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Locale&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;language&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iso_639_1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span style="color:#6E9CBE"&gt;:translation&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;
    &lt;span class="ident"&gt;render&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:text&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;And then you need to extend Rails' route parser to attach a URL to your controller.  (&lt;code&gt;alias_method_chain&lt;/code&gt; to the rescue!)&lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#CC7833"&gt;module &lt;/span&gt;&lt;span class="module"&gt;MapperExtensions&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.included&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:alias_method_chain&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:google_caching&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize_with_google_caching&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span style="color:#BC9458"&gt;#we have to add ours FIRST, otherwise the final line of the regular routes.rb is usually a catchall that would intercept OUR route&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_route&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span style="color:#A5C261"&gt;/cache_google_translation&lt;/span&gt;&lt;span class="punct"&gt;',{&lt;/span&gt;&lt;span style="color:#6E9CBE"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;google/tricks&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;cache_google_translation&lt;/span&gt;&lt;span class="punct"&gt;'})&lt;/span&gt;
    &lt;span class="ident"&gt;initialize_without_google_caching&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Finally, in your plugin's &lt;code&gt;init&lt;/code&gt; file you just attach these classes into Rails:&lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#DA4939"&gt;ActionController&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Routing&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;RouteSet&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Mapper&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:include&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#DA4939"&gt;Google&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;MapperExtensions&lt;/span&gt;
&lt;span style="color:#DA4939"&gt;ActionView&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Helpers&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;AssetTagHelper&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:include&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#DA4939"&gt;Google&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;Javascript&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;And that's it!  Well, not quite.  Did you notice the reference to Locale.translator.put_in_cache?  If you want to make sure that the auto-translations in your database are easily distinguishable so that you can have them manually translated later (machine translation isn't &lt;i&gt;quite&lt;/i&gt; there yet!) then you have to add an extra step.  It was easy enough to use a manual update statement instead of Locale.set_translation, which allowed me to set "built_in = 2" (that's how you recognize the auto-translations).  But then the 800 lb. gorilla gets in the way. Globalize maintains a separate cache of translations in memory to avoid wear and tear on the database, but if you don't update the copy in memory as well, Globalize will never actually USE your cached version!  It's a protected variable, so one more module extension:&lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#CC7833"&gt;module &lt;/span&gt;&lt;span class="module"&gt;LocalizeCacheAccess&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;put_in_cache&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;language&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;translation&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span style="color:#D0D0FF"&gt;@cache&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&lt;span class="expr"&gt;#{key}&lt;/span&gt;:&lt;span class="expr"&gt;#{language}&lt;/span&gt;:1&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;translation&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;and then include it in your app with&lt;/p&gt;
&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:12px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#DA4939"&gt;Globalize&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;DbViewTranslator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:include&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#DA4939"&gt;Google&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span style="color:#DA4939"&gt;LocalizeCacheAccess&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;And that's it!  Now you're REALLY done!  To get all of this code in a simple Rails plugin, download &lt;a href="http://www2.killswitchcollective.com/articles/globalize_with_google.zip"&gt;globalize_with_google.zip&lt;/a&gt; and unpack it in &lt;code&gt;#{RAILS_ROOT}/vendor/plugins/&lt;/code&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 13 Jun 2008 14:50:13 -0700</pubDate>
      <link>http://www.killswitchcollective.com/articles/23</link>
      <guid>http://www.killswitchcollective.com/articles/23</guid>
    </item>
    <item>
      <title>Wrapping Up View Repetition with GiftWrap</title>
      <category>Development</category>
      <description>&lt;style&gt;
pre {
margin: 15px 0;
}
div.update {
  border: 4px solid #9AB223;
  padding: 10px;
line-height: 1.3;
}
&lt;/style&gt;
&lt;p style="font-style: italic; color: #777; font-size: 10px;"&gt;
  NOTE: My thanks go out to the guys at RailsConf who attended my "Birds of a Feather" talk about DRYing up views using wrapper helper classes. They gave me the idea to abstract my ideas one level further into its own class and now we have GiftWrap -- I hope you guys can make good use of it!
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/chrisjpowers/giftwrap/tree/master"&gt;Just get GiftWrap now!&lt;/a&gt;&lt;/p&gt;

&lt;div class="update"&gt;
  UPDATED: GiftWrap has been now been updated to allow for using wrapper partials with the &lt;code&gt;use_partial&lt;/code&gt; method rather than the &lt;code&gt;before_yield&lt;/code&gt; and &lt;code&gt;after_yield&lt;/code&gt; methods. Read the &lt;a href="http://github.com/chrisjpowers/giftwrap/tree/master"&gt;README file&lt;/a&gt; to see examples of how to use this new functionality.
&lt;/div&gt;

&lt;h3&gt;Blocks and Procs&lt;/h3&gt;

&lt;p&gt;I have always been very impressed by the way the Rails &lt;code&gt;form_for&lt;/code&gt; helper method works. I loved that you never had to remember the &lt;code&gt;&amp;lt;/form&amp;gt;&lt;/code&gt; closing tag or use the silly (and very deprecated) &lt;code&gt;end_form_tag&lt;/code&gt; helper method. Perhaps what I was most drawn to about the method was how the block acted as a "closure" -- not just in the programming sense, but also in a semantic sense. It struck me as very beautiful that this method could create a mini-environment of rules and abilities, allow anything to happen within this environment and then close that context until the next time.
&lt;/p&gt;

&lt;p&gt;And that, of course, is the beauty of using blocks and procs in Ruby.&lt;/p&gt;

&lt;p&gt;So why do these blocks in the view stand out to me when their counterparts in models and controllers simply aren't that big of a deal? I think part of the reason is that you don't see blocks in the view very often. The &lt;code&gt;content_tag&lt;/code&gt; helper takes a block, but the method itself isn't really that helpful. Looping methods like &lt;code&gt;each&lt;/code&gt; take a block, of course, but again that's nothing to blog about. &lt;code&gt;Form_for&lt;/code&gt; seems to be a fairly unique method within the Rails framework.&lt;/p&gt;

&lt;p&gt;I have found, however, that using blocks within the view to wrap and contextualize markup can be extremely helpful in DRYing up views and making markup more modular.&lt;/p&gt;

&lt;h3&gt;Nice and Easy Blocks with GiftWrap&lt;/h3&gt;

&lt;p&gt;Creating a method that works like &lt;code&gt;form_for&lt;/code&gt; is a little tricky. First you have to create a helper class with a series of methods for generating the wrapper markup and anything else you need. Then you need to create the helper method itself, which initializes your class, uses the confusing &lt;code&gt;concat&lt;/code&gt; method to write your wrapper markup to the ERB buffer, and then yields the class instance to your block.&lt;/p&gt;

&lt;p&gt;Thankfully, I was able to abstract all the common elements into the &lt;code&gt;GiftWrap&lt;/code&gt; class. By subclassing &lt;code&gt;GiftWrap&lt;/code&gt; and following a couple simple conventions, you will easily be able to create wrapper classes that can bring clarity and DRYness to your views.&lt;/p&gt;

&lt;h3&gt;Example: The Help Popup&lt;/h3&gt;

&lt;p&gt;The site that I am currently building requires a large number of "question mark" buttons -- if the user is unsure of what a certain section of the site does, a quick press of help button gives them a simple popup box with an explanation. The markup for these buttons/popups looked like this:&lt;/p&gt; 

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:14px;font-size:12px;padding:6px;"&gt;
&amp;lt;p class=&amp;quot;help_popup_link&amp;quot; id=&amp;quot;feature_help_popup_link&amp;quot;&amp;gt;
  &amp;lt;a href=&amp;quot;#&amp;quot; onclick=&amp;quot;$(this).up(&amp;#x27;.help_popup_link&amp;#x27;).next().toggle(); return false;&amp;quot;&amp;gt;Help&amp;lt;/a&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;div class=&amp;quot;help_popup&amp;quot; id=&amp;quot;feature_help_popup&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;
  &amp;lt;p class=&amp;quot;close_button&amp;quot;&amp;gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; onclick=&amp;quot;$(this).up(&amp;#x27;.help_popup&amp;#x27;).hide(); return false;&amp;quot;&amp;gt;Close&amp;lt;/a&amp;gt;
 &amp;lt;/p&amp;gt;
 &amp;lt;!-- any amount of markup should be insertable here --&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;These popups will all share similar markup, but their content can vary wildly. I quickly ruled out using partials to DRY my view -- I need too much flexibility in what goes inside this wrapper markup.&lt;/p&gt;

&lt;p&gt;I chose instead to use a wrapper class that inherits from &lt;code&gt;GiftWrap&lt;/code&gt;.&lt;/p&gt;

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:14px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#CC7833"&gt;class &lt;/span&gt;&lt;span class="class"&gt;HelpPopup&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#DA4939"&gt;GiftWrap&lt;/span&gt;

  &lt;span class="ident"&gt;before_yield&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:help_button&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:open_block&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:close_button&lt;/span&gt;
  &lt;span class="ident"&gt;after_yield&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:close_block&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span style="color:#D0D0FF"&gt;@id&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;id&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;private&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;help_button&lt;/span&gt;
    &lt;span class="punct"&gt;%Q{&lt;/span&gt;&lt;span style="color:#A5C261"&gt;
      &amp;lt;p class=&amp;quot;help_popup_link&amp;quot; id=&amp;quot;&lt;span class="expr"&gt;#{@id}&lt;/span&gt;_help_popup_link&amp;quot;&amp;gt;
        &lt;span class="expr"&gt;#{link_to_function 'Help', &amp;quot;$(this).up('.help_popup_link').next().toggle()&amp;quot;}&lt;/span&gt;
      &amp;lt;/p&amp;gt;
    &lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;close_button&lt;/span&gt;
    &lt;span class="punct"&gt;%Q{&lt;/span&gt;&lt;span style="color:#A5C261"&gt;
      &amp;lt;p class=&amp;quot;close_button&amp;quot;&amp;gt;
        &lt;span class="expr"&gt;#{link_to_function 'Close', &amp;quot;$(this).up('.help_popup').hide()&amp;quot;}&lt;/span&gt;
      &amp;lt;/p&amp;gt;
    &lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#BC9458"&gt;# Called before yielding a block to this instance&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;open_block&lt;/span&gt;
    &lt;span class="punct"&gt;%Q{&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;div class=&amp;quot;help_popup&amp;quot; id=&amp;quot;&lt;span class="expr"&gt;#{@id}&lt;/span&gt;_help_popup&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#BC9458"&gt;# Called after yielding a block to this instance&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;close_block&lt;/span&gt;
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

&lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;As you probably have guessed, the methods passed into the &lt;code&gt;before_yield&lt;/code&gt; method will be called in order before the block is run and the returned values will be added to the markup. The &lt;code&gt;after_yield&lt;/code&gt; method acts the same.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;GiftWrap&lt;/code&gt; is subclassed, a helper method is dynamically generated as the underscored name of the new class. In this example the helper method will be named &lt;code&gt;help_popup&lt;/code&gt; because the class is named &lt;code&gt;HelpPopup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The implementation now looks like this in the view...&lt;/p&gt;

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:14px;font-size:12px;padding:6px;"&gt;
&amp;lt;% help_popup :feature do %&amp;gt;
  &amp;lt;p&amp;gt;This is explanation text within the popup box.&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;More text here.&amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;This generates this markup...&lt;/p&gt;

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:14px;font-size:12px;padding:6px;"&gt;
&amp;lt;p class=&amp;quot;help_popup_link&amp;quot; id=&amp;quot;feature_help_popup_link&amp;quot;&amp;gt;
  &amp;lt;a href=&amp;quot;#&amp;quot; onclick=&amp;quot;$(this).up(&amp;#x27;.help_popup_link&amp;#x27;).next().toggle(); return false;&amp;quot;&amp;gt;Help&amp;lt;/a&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;div class=&amp;quot;help_popup&amp;quot; id=&amp;quot;feature_help_popup&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;
  &amp;lt;p class=&amp;quot;close_button&amp;quot;&amp;gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; onclick=&amp;quot;$(this).up(&amp;#x27;.help_popup&amp;#x27;).hide(); return false;&amp;quot;&amp;gt;Close&amp;lt;/a&amp;gt;
 &amp;lt;/p&amp;gt;
 &amp;lt;p&amp;gt;This is explanation text within the popup box.&amp;lt;/p&amp;gt;
 &amp;lt;p&amp;gt;More text here.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Example: Boxes with Rounded Corners&lt;/h3&gt;

&lt;p&gt;Another quality of this site is that it uses boxes with rounded corners extensively. Using a GiftWrap subclass I can remove all the repetitive wrapper markup needed for a 'sliding doors' approach, but that's not all! I also want to use a standard set of markup and CSS classes for my subheaders and "more" links, so it would be great to encapsulate that within this block as well. Here's how we can do it...&lt;/p&gt;

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:14px;font-size:12px;padding:6px;"&gt;&lt;span style="color:#CC7833"&gt;class &lt;/span&gt;&lt;span class="class"&gt;RoundCornerBox&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#DA4939"&gt;GiftWrap&lt;/span&gt;
  &lt;span class="ident"&gt;before_yield&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:header&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:open_divs&lt;/span&gt;
  &lt;span class="ident"&gt;after_yield&lt;/span&gt; &lt;span style="color:#6E9CBE"&gt;:close_divs&lt;/span&gt;

  &lt;span style="color:#BC9458"&gt;# A new instance of RoundCornerBox will be instantiated each time the&lt;/span&gt;
  &lt;span style="color:#BC9458"&gt;# dynamic round_corner_box is called in the view. The arguments passed into&lt;/span&gt;
  &lt;span style="color:#BC9458"&gt;# the helper method are passed on directly to the initialize method.&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;={})&lt;/span&gt;
    &lt;span style="color:#D0D0FF"&gt;@name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;
    &lt;span style="color:#D0D0FF"&gt;@header&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span style="color:#6E9CBE"&gt;:header&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#BC9458"&gt;# # # These methods can be used within your wrapper block. # # #&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;subheader&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;h4 class='subheader'&amp;gt;&lt;span class="expr"&gt;#{text}&lt;/span&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;more_button&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;url&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;p class='more_button'&amp;gt;&lt;span class="expr"&gt;#{link_to text, url}&lt;/span&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;private&lt;/span&gt;

  &lt;span style="color:#BC9458"&gt;# # # These methods will only be used internally for creating the wrapper markup. # # #&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;header&lt;/span&gt;
    &lt;span style="color:#D0D0FF"&gt;@header&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;h3 class='round_corner_box_header'&amp;gt;&lt;span class="expr"&gt;#{@header}&lt;/span&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;open_divs&lt;/span&gt;
    &lt;span class="punct"&gt;%Q{&lt;/span&gt;&lt;span style="color:#A5C261"&gt;
      &amp;lt;div class=&amp;quot;round_corner_box_top&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;round_corner_box_bottom&amp;quot; id=&amp;quot;&lt;span class="expr"&gt;#{@name}&lt;/span&gt;_round_corner_box&amp;quot;&amp;gt;
    &lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;

  &lt;span style="color:#CC7833"&gt;def &lt;/span&gt;&lt;span class="method"&gt;close_divs&lt;/span&gt;
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#A5C261"&gt;&amp;lt;/div&amp;gt;&lt;span class="escape"&gt;\n&lt;/span&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span style="color:#CC7833"&gt;end&lt;/span&gt;
&lt;span class="ident"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Now here's how we can implement those public methods...&lt;/p&gt;

&lt;pre style="background-color:#2B2B2B;color:#E6E1DC;padding:6px;overflow:auto;line-height:14px;font-size:12px;padding:6px;"&gt;&lt;code&gt;
&amp;lt;% round_corner_box :news, :header =&amp;gt; &amp;quot;Today&amp;#x27;s News&amp;quot; do |b| %&amp;gt;
  &amp;lt;%= b.subheader &amp;quot;Top Story&amp;quot; %&amp;gt;
  &amp;lt;p&amp;gt;Today was a very exciting day in the news...&amp;lt;/p&amp;gt;
  &amp;lt;%= b.more_button &amp;quot;Full Story&amp;quot;, top_story_path %&amp;gt;

  &amp;lt;%= b.subheader &amp;quot;Lesser Story&amp;quot; %&amp;gt;
  &amp;lt;p&amp;gt;This story is definitely less important than the top story...&amp;lt;/p&amp;gt;
  &amp;lt;%= b.more_button &amp;quot;Full Story&amp;quot;, bottom_story_path %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;With the &lt;code&gt;GiftWrap&lt;/code&gt; class, you now can easily harness the power and flexibility of using wrapper classes in your view to DRY up your code. &lt;a href="http://github.com/chrisjpowers/giftwrap/tree/master"&gt;So go ahead, get &lt;code&gt;GiftWrap&lt;/code&gt; now!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have ideas for how to improve or extend &lt;code&gt;GiftWrap&lt;/code&gt;, please feel free to fork the Git repository or leave comments.&lt;/p&gt;</description>
      <pubDate>Tue, 03 Jun 2008 13:33:38 -0700</pubDate>
      <link>http://www.killswitchcollective.com/articles/22</link>
      <guid>http://www.killswitchcollective.com/articles/22</guid>
    </item>
  </channel>
</rss>
