2011-12-01 69 views
1

我有一個方法將提供一個模型對象的數組。其中一些模型的屬性很容易通過使用SQL的幫助來排序。我的意思是,使用。查找(:condition => {})Ruby on Rails:排序對象集合

問題是其他的一些屬性不是。在展示前必須進行計算,修改或做其他事情。然後,我找到了使用集合分類對其進行分類的方法。這是,collection.sort {| a,b | a.something_to_sort < => b.something_to_sort}

OK!這是有效的。但問題是,是否有可能使某些東西變成動態變量的東西?例如,我想從UI添加一個參數,並將其分配給something_to_sort像下面,

HTML

<select name="sort"> 
    <option value="name">Name</option> 
    <option value="age">Age</option> 
    <option value="activity.category">Activity</option> 
    <option value="tax.calculate_personal_income_tax">Income Tax</option> 
    <option value="tax.calculate_withholding_tax">Withholding Tax</option> 
    <option value="doctor.name">Doctor's Name</option> 
</select> 

Rails的

params[:sort] ||= "Age" 
@people = Person.find(:all) 
@people.sort{|a,b| a.params[:sort] <=> b.params[:sort]} #Note that this is an incorrect syntax 

有沒有辦法做到這一點通過不必爲每個排序選項編寫一個排序塊?

附加#1

我只是嘗試這樣做,這是工作了一段排序選項

@people.sort{|a,b| a.send(params[:sort]) <=> b.send(params[:sort])} 

這適用於名字和年齡,因爲他們是人的特性(和它的作品了也是peopls的方法)。但對於協會來說,例如tax.calculate_personal_income_tax,事實並非如此。

所以,我的同事告訴我,以創造新的人的方法,calculate_personal_income_tax,然後從tax.calculate_personal_income_tax更改選項值calculate_personal_income_tax使發送方法將能夠找到這種方法...

def calculate_personal_income_tax 
    tax.calculate_personal_income_tax 
end 

但是,這不是我真正想要的。因爲我相信必須有一種方法來訪問這種關聯方法,而無需定義新的模型方法。如果我選擇這樣做,有一天人們的模型變得更大,更多的屬性,更多的信息進行排序和顯示。然後,會有很多像這樣的方法。

另一個原因是,如果我必須定義一個新的方法,該方法應該做一些邏輯,計算或其他,而不僅僅是從其他模型中檢索數據。

附加#2

最後,我只是發現通過添加參數傳遞給了找到方法,訪問其他模型屬性的方式:加入:選擇

@people = Person.find(:all, :select => "persons.*, tax.tax_rate AS tax_rate", :joins => :tax, :condition => {some conditions}) 

的,其結果將是加入一個表。然後,我用send(params [:sort])這個東西來幫我排序我想要的屬性。

+0

所以你*不能*使用SQL來排序結果? –

+0

是的,一些顯示列不能通過SQL語句進行排序(或者,我不知道如何去做)。其中一些太複雜,因爲它涉及到很多相關的模型 –

回答

1
@people.sort {|a, b| a.send(params[:sort]) <=> b.send(params[:sort])} 
+0

感謝隊友,我也發現了這一點。問題是,它適用於人們的屬性或方法。但不是它的關聯(如tax.calculate_personal_income_tax)......無論如何,再次感謝隊友。 –

1
params[:sort] ||= "age" 
method_chain = params[:sort].split(".") 
@people = Person.find(:all) 
@sorted_people = 
    @people.sort_by do |person| 
    method_chain.inject(person) do |memo,method| 
     memo.send(method) 
    end 
    end 

這假定在PARAMS傳遞的值[:排序]總是能一起在指定的順序被鏈接有效方法名。你要記住,任何可以通過params散列,所以這是非常不安全的,如果暴露給不可信用戶(例如params[:sort] = "destroy"。哎呀。)

此外,如果你可以在SQL中做到這一點你會獲得更好的表現。

事實上,我越是看這個,越是看起來不好主意。

0

我有一個戰利品系統,這是基於一個計算值,這是基於一個可以改變的參考表。由於價值計算,它可能來自任何地方。

我的玩家/ index.html.rb看起來像。

<h1>Players</h1> 
<table> 
    <tr> 
    <th>Name</th> 
    <%= generate_headings(params) %> 
    </tr> 

    <% players.each do |player| %> 
    <tr> 
     <td><%= player.name %></td> 
     <% LootType.all.each do |loot_type| %> 
     <td><%= player.loot_rate(loot_type.name) %></td> 
     <% end %> 
    <tr> 
    <% end %> 
</table> 

的loot_rate功能被稱爲 「類型+ 1的玩家襲擊/贓物」 運算在兩個相關的表(player.raids和player.items)。

的generate_headings功能是players_helper.rb,它看起來像:

def generate_headings(params = {}) 
    sort = params[:sort] 
    headings = "" 
    LootType.all.each do |loot_type| 
    heading_text = "#{loot_type.name} Rate" 
    if (sort == loot_type.name) 
     column_heading = "<th>#{heading_text}</th>" 
    else 
     heading_url = "/players?sort=#{loot_type.name}" 
     column_heading = "<th>#{link_to heading_text, heading_url}</th>" 
    end 
    headings += column_heading 
    end 
    headings.html_safe 
end 

在players_controller.rb的我的索引行動,我有:

def index 
    sort = params[:sort] 
    if !sort 
    @players.sort! { |a,b| a.name <=> b.name } 
    else 
    @players.sort! { |a,b| b.loot_rate(sort) <=> a.loot_rate(sort) } # Reverse sort (for my purposes) 
    end 

    respond_to do |format| 
    format.html 
    format.json {render :json => @players } 
    end 
end 

這意味着,當我添加或刪除我的系統中的「戰利品類型」,並且玩家列表自動允許用戶按照這些類型進行排序。

囉嗦的答案,但希望它有幫助。