title: Ruby/Rails Method Help
body: <p>So, I'm pretty much a newbie at creating ruby methods. I've got the following method from a gem (meta_search), but I need to change the default behavior. Here's the method:</p>
  
  <pre><code>def sort_link(builder, attribute, *args)
    raise ArgumentError, "Need a MetaSearch::Builder search object as first param!" unless builder.is_a?(MetaSearch::Builder)
    attr_name = attribute.to_s
    name = (args.size &gt; 0 &amp;&amp; !args.first.is_a?(Hash)) ? args.shift.to_s : builder.base.human_attribute_name(attr_name)
    prev_attr, prev_order = builder.search_attributes['meta_sort'].to_s.split('.')
    current_order = prev_attr == attr_name ? prev_order : nil
    new_order = current_order == 'asc' ? 'desc' : 'asc'
    options = args.first.is_a?(Hash) ? args.shift : {}
    html_options = args.first.is_a?(Hash) ? args.shift : {}
    css = ['sort_link', current_order].compact.join(' ')
    html_options[:class] = [css, html_options[:class]].compact.join(' ')
    options.merge!(
      builder.search_key =&gt; builder.search_attributes.merge(
        'meta_sort' =&gt; [attr_name, new_order].join('.')
      )
    )
    link_to [ERB::Util.h(name), order_indicator_for(current_order)].compact.join(' ').html_safe,
            url_for(options),
            html_options
  end
  </code></pre>
  
  <p>This method returns a sort link for a search. The output looks like this:</p>
  
  <pre><code>&lt;a class="sort_link asc" href="/photos?search[meta_sort]=average_rating.desc"&gt;Best Photography ▲&lt;/a&gt;
  </code></pre>
  
  <p>Here's the problem: this method assumes that you want to sort in ascending order on the first click, and descending order on the second. I want the opposite behavior. I see that I could change this...</p>
  
  <pre><code>new_order = current_order == 'asc' ? 'desc' : 'asc'
  </code></pre>
  
  <p>to this...</p>
  
  <pre><code>new_order = current_order == 'desc' ? 'asc' : 'desc'
  </code></pre>
  
  <p>...but that just reverses the situation. What I really need is to be able to specify an option and reverse the behavior if that option is passed.</p>
  
  <p>So here's my problem: I don't really understand how the *args are passed. From what I can tell these lines are taking the option and html_option hashes for rails link_to method...</p>
  
  <pre><code>options = args.first.is_a?(Hash) ? args.shift : {}
  html_options = args.first.is_a?(Hash) ? args.shift : {}
  </code></pre>
  
  <p>What I'd like to do is add a custom option to the options hash, and if that option is defined reverse the sort equation. I tried to do this...</p>
  
  <pre><code>if defined? options[:sort_preference] &amp;&amp; options[:sort_preference]==:desc
    new_order = current_order == 'desc' ? 'asc' : 'desc'
    options.delete(:sort_preference)
  else
    new_order = current_order == 'asc' ? 'desc' : 'asc'
    options.delete(:sort_preference)
  end
  </code></pre>
  
  <p>... but that didn't work, it just kept the standard behavior and passed :sort_preference into the URL like so:</p>
  
  <pre><code>&lt;a class="sort_link asc" href="/photos?search[meta_sort]=average_rating.desc&amp;sort_preference=desc"&gt;Best Photography ▲&lt;/a&gt;
  </code></pre>
  
  <p>In the link above, <code>sort_preference</code> shouldn't appear in the URL, and <code>search[meta_sort]</code> should be <code>average_rating.asc</code> -- since the link shows the opposite of what rendered.</p>
  
  <p>So, obviously, my attempt didn't work because I don't really understand what's going on in this method. What I'm hoping for in answer to this question is:</p>
  
  <ul>
  <li>A little help understanding how *args works</li>
  <li>An explanation of why my attempt to add an option to this method failed</li>
  <li>An example of how to fix it</li>
  </ul>
  
  <p>Thank you very much for taking a look!</p>