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:
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 > 0 && !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 => builder.search_attributes.merge( 'meta_sort' => [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 This method returns a sort link for a search. The output looks like this:
<a class="sort_link asc" href="/photos?search[meta_sort]=average_rating.desc">Best Photography ▲</a> 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...
new_order = current_order == 'asc' ? 'desc' : 'asc' to this...
new_order = current_order == 'desc' ? 'asc' : 'desc' ...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.
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...
options = args.first.is_a?(Hash) ? args.shift : {} html_options = args.first.is_a?(Hash) ? args.shift : {} 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...
if defined? options[:sort_preference] && 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 ... but that didn't work, it just kept the standard behavior and passed :sort_preference into the URL like so:
<a class="sort_link asc" href="/photos?search[meta_sort]=average_rating.desc&sort_preference=desc">Best Photography ▲</a> In the link above, sort_preference shouldn't appear in the URL, and search[meta_sort] should be average_rating.asc -- since the link shows the opposite of what rendered.
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:
- A little help understanding how *args works
- An explanation of why my attempt to add an option to this method failed
- An example of how to fix it
Thank you very much for taking a look!