2011-04-03 230 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