Ruby on Rails:排序对象集合
我有一个方法将提供一个模型对象的数组。其中一些模型的属性很容易通过使用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])这个东西来帮我排序我想要的属性。
@people.sort {|a, b| a.send(params[:sort]) <=> b.send(params[:sort])}
感谢队友,我也发现了这一点。问题是,它适用于人们的属性或方法。但不是它的关联(如tax.calculate_personal_income_tax)......无论如何,再次感谢队友。 –
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中做到这一点你会获得更好的表现。
事实上,我越是看这个,越是看起来不好主意。
我有一个战利品系统,这是基于一个计算值,这是基于一个可以改变的参考表。由于价值计算,它可能来自任何地方。
我的玩家/ 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
这意味着,当我添加或删除我的系统中的“战利品类型”,并且玩家列表自动允许用户按照这些类型进行排序。
啰嗦的答案,但希望它有帮助。
所以你*不能*使用SQL来排序结果? –
是的,一些显示列不能通过SQL语句进行排序(或者,我不知道如何去做)。其中一些太复杂,因为它涉及到很多相关的模型 –