2011-04-03 184 views
0

所以,我几乎是创建ruby方法的新手。我从gem(meta_search)获得了以下方法,但我需要更改默认行为。以下是方法:Ruby/Rails方法帮助

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 

此方法返回搜索的排序链接。输出看起来是这样的:

<a class="sort_link asc" href="/photos?search[meta_sort]=average_rating.desc">Best Photography ▲</a> 

这里的问题:这种方法假定您想按升序进行排序第一次点击,并在第二降序排列。我想要相反的行为。我看到,我可以改变这个...

new_order = current_order == 'asc' ? 'desc' : 'asc' 

这个...

new_order = current_order == 'desc' ? 'asc' : 'desc' 

...但只是反转的情况。我真正需要的是能够指定一个选项并在该选项通过时反转行为。

所以这里是我的问题:我真的不明白如何通过*参数。从我可以告诉这些线路正在服用的选项,html_option哈希为Rails的link_to方法...

options = args.first.is_a?(Hash) ? args.shift : {} 
html_options = args.first.is_a?(Hash) ? args.shift : {} 

我希望做的是一个自定义的选项添加到选项哈希值,并且如果该选项定义反转排序方程。我试图做到这一点...

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 

...但没有奏效,它只是不停的标准行为,并通过:sort_preference到URL像这样:

<a class="sort_link asc" href="/photos?search[meta_sort]=average_rating.desc&sort_preference=desc">Best Photography ▲</a> 

在上面的链接,sort_preference不应该出现在URL中,并且search[meta_sort]应该是average_rating.asc - 因为链接显示与呈现的内容相反。

所以,显然,我的尝试没有奏效,因为我不太明白这种方法发生了什么。就是我在回答希望对这个问题是:

  • 了解如何* ARGS一点帮助工作
  • 为什么我尝试的选项添加到该方法的解释未能
  • 的例子如何修复它

非常感谢您的参观!

回答

1

*args只是表示您可以传递无限数量的参数。因此,此方法首先需要2个参数(构建器&属性),然后您可以传递任意数量的参数。这里是正在发生的事情的方法有关的args来描述:

  1. 如果传递给此方法的第三个参数是不是一个哈希值,那么它将设置ARG作为名称,并删除它(args.shift ),否则使用构建器名称。

  2. 然后它看看下一个arg(这将是第4个)。如果它是一个散列,那么它将选项设置为该arg并删除该arg,否则将其设置为空散列。

  3. 然后看看下一个参数(第5个参数)。如果它是一个散列,那么它将其设置为html_options并删除该arg,否则将html设置为{}。

使用args *可以使调用该方法稍微干净些(虽然方法中的实现可能不会)。如果你没有一个“名”来传递,而不是做这样的:

sort_link(some_builder,some_attribute,nil,options) 

,你可以这样做:

sort_link(some_builder,some_attribute,options) 

它不会强迫你,添加精氨酸的名字,如果你没有一个。

因此,为了您的代码正常工作,此方法需要将选项作为第4个参数,并且选项哈希需要包含:sort_preferences。代码看起来是什么叫sort_link?在获得此方法之前,您需要将该选项插入到该散列中。

+0

要回答你的问题,调用代码为:'= sort_link @search ,:average_rating,“Best Photography”,:sort_preference =>:desc' – Andrew 2011-04-04 03:26:30

+0

好吧,我现在明白了 - 我需要移动'options = args.first.is_a?(Hash)? args.shift:{}'为了使我的if语句正常工作。一旦这条线向上移动,它就会起作用。感谢您的解释,这对我们有很大帮助! – Andrew 2011-04-04 04:38:12

1

此方法假定您想在第一次单击时按升序排序,在第二次按降序排序。我想要相反的行为。

meta_search gem支持这一点。没有必要修改宝石的代码。在您的控制器中,在查询了您的数据之后,将@search对象的meta_sort属性设置为您想要的字段和排序顺序。加载视图时,您的数据将按预期排序。

例如,在一个帖子控制器,你会做以下设置默认排序的标题字段,降:

def index 
    @search = Post.search(params[:search]) 
    @search.meta_sort ||= 'title.desc' 
    @posts= @search.all 
end 
+0

嘿,谢谢你 - 我仍然认为默认行为应该可以内联而不是在控制器中更改,但这是一个很好的解决方案。 – Andrew 2011-05-27 06:21:19