2012-11-01 56 views
3

我的搜索方法很臭臃腫,我需要一些幫助來重構它。我是新來的紅寶石,而我還沒有想出如何有效地利用它,導致臃腫的方法是這樣的:如何在Rails模型中重構複雜的搜索邏輯

# discussion.rb 
    def self.search(params) 
    # If there is a search query, use Tire gem for fulltext search 
    if params[:query].present? 
     tire.search(load: true) do 
     query { string params[:query] } 
     end 

    # Otherwise grab all discussions based on category and/or filter 
    else 

     # Grab all discussions and include the author 
     discussions = self.includes(:author) 

     # Filter by category if there is one specified 
     discussions = discussions.where(category: params[:category]) if params[:category] 

     # If params[:filter] is provided, user it 
     if params[:filter] 
     case params[:filter] 
     when 'hot' 
      discussions = discussions.open.order_by_hot 
     when 'new' 
      discussions = discussions.open.order_by_new 
     when 'top' 
      discussions = discussions.open.order_by_top 
     else 
      # If params[:filter] does not match the above three states, it's probably a status 
      discussions = discussions.order_by_new.where(status: params[:filter]) 
     end 
     else 

     # If no filter is passed, just grab discussions by hot 
     discussions = discussions.open.order_by_hot 
     end 
    end 
    end 

    STATUSES = { 
    question: %w[answered], 
    suggestion: %w[started completed declined], 
    problem: %w[solved] 
    } 

    scope :order_by_hot, order('...') DESC, created_at DESC") 
    scope :order_by_new, order('created_at DESC') 
    scope :order_by_top, order('votes_count DESC, created_at DESC') 

這是可以通過一個過濾(或者不是)一個模型的探討類別:questionproblemsuggestion

所有討論或單個類別可以進一步篩選hot,new,votesstatus。狀態是模型中的一個散列,它取決於類別具有多個值(只有在出現params [:category]時纔會顯示狀態過濾器)。

複雜的問題是使用輪胎

一個全文檢索功能,但我的控制器看起來不錯,整潔:

def index 
    @discussions = Discussion.search(params) 
    end 

我可以幹這件事/重構它一點點,也許使用元編程或塊?我設法從控制器中提取出來,但後來用完了想法。我不知道Ruby是否足夠進一步採取這一做法。

回答

3

對於初學者來說,「根據類別和/或過濾器獲取所有討論」可以是一種單獨的方法。如果那麼否則,如果情況else語句

filter = params[:filter] 

您可以使用

if [:hot, :new, :top].incude? filter 
    discussions = discussions.open.send "order_by_#{filter}" 
... 

而且,從要素:

params[:filter]被重複很多次,所以採取了在頂部。我寧願打入不同的方法,並提前返回:

def do_something 
    return 'foo' if ... 
    return 'bar' if ... 
    'baz' 
end 

discussions = discussions...多次出現,但看起來怪怪的。你可以用return discussions...代替嗎?

爲什麼常數STATUSES出現在最後?通常常數出現在模型的頂部。

一定要在重構之前編寫所有測試。

要回應註釋約return 'foo' if ...

考慮:

def evaluate_something 
    if a==1 
    return 'foo' 
    elsif b==2 
    return 'bar' 
    else 
    return 'baz' 
    end 
end 

我建議重構這:

def evaluate_something 
    return 'foo' if a==1 
    return 'bar' if b==2 
    'baz' 
end 

也許你可以重構你的一些if..then的。 .else..if語句。

推薦書:Clean Code

+0

完美。謝謝。我結束了這個:http://pastie.org/5166966 - 至於常數,他們在頂部;爲了清晰起見,我只是將它們粘貼在底部。 – dee

+0

PS:不過,不確定你的意思是'返回'腳'if'。而重複的「討論=討論」,我把它拿出來了,但是我必須把它留給'where'從句,否則沒有什麼東西會回來。 – dee

+0

@dee - 答案已更新以回覆您的評論。 –