我有一个方法可以检索某些区域中存在的组。组被赋予country_id,region_id和city_id
用户界面提供了三个选择框,用于选择国家/地区,该国家/地区以及该地区的城市。要查找特定城市中的所有群组,我有以下代码:
@groups = Group.find(:all, :conditions => {:city_id => params[:city_id]})
这一切都运行正常,但我还希望它在未指定较低条件时查找区域中的所有组。例如,如果给出了一个国家和地区,而不是城市,我想在该地区找到它。
我正在做的是:
if !params[:city_id].nil?
@groups = Group.find(:all, :conditions => {:city_id => params[:city_id]})
else
if !params[:region_id].nil?
@groups = Group.find(:all, :conditions => {:region_id => params[:region_id]})
else
@groups = Group.find(:all, :conditions => {:country_id => params[:country_id]})
end
end
这非常有效,但看起来效率有点低。我这样做是最好的方式还是可以简化一下?
我的一个想法是让一个查找检查所有参数,但我无法弄清楚如何有效地'忽略'参数是零 - 我的主要想法是检查哪些没有设置并将它们设置为类似'*'或'true'的东西,但这不是SQL玩游戏的方式。
答案 0 :(得分:1)
如果params
中的每个值都是:conditions
的候选者,您可以这样做:
@groups = Group.all(:conditions => params.reject { |idx, val| val.nil? })
这只是从params中抛出nil值并使用条件的剩余值。
如果您不想使用params
中的所有值,则有两种选择。您可以在原始代码中摆脱一堆冗余:
conditions = if !params[:city_id].nil?
{ :city_id => params[:city_id] }
elsif !params[:region_id].nil?
{ :region_id => params[:region_id] }
else
{ :country_id => params[:country_id] }
end
@groups = Group.all(:conditions => conditions)
你可以再敲几行,但它牺牲了一点可读性IMO:
conditions = if !params[:city_id].nil? then { :city_id => params[:city_id] }
elsif !params[:region_id].nil? then { :region_id => params[:region_id] }
else { :country_id => params[:country_id] }
end
或者你可以这样做:
conditions = [:city_id, :region_id, :country_id].inject({}) do |hsh, sym|
hsh[sym] = params[sym] unless params[sym].nil?
hsh
end
@groups = Group.all(:conditions => conditions)
这样做的好处是您不需要为每个符号添加另一个条件。
答案 1 :(得分:1)
听起来像命名范围的工作:
class Group < ActiveRecord::Base
named_scope :in_city, lambda { |city_id| {
:conditions => { :city_id => city_id }
}}
named_scope :in_region, lambda { |region_id | {
:conditions => { :region_id => region_id }
}}
named_scope :in_country, lambda { |country_id | {
:conditions => { :country_id => country_id }
}}
end
这为限制组记录建立了一些简单的范围。据推测,您已正确索引数据库,因此可以快速解决这些问题。
控制器更容易实现:
def index
@group_scope = Group
if (!params[:city_id].blank?)
@group_scope = @group_scope.in_city(params[:city_id])
elsif (!params[:region_id].blank?)
@group_scope = @group_scope.in_region(params[:region_id])
elsif (!params[:country_id].blank?)
@group_scope = @group_scope.in_country(params[:country_id])
end
@groups = @group_scope.all
end
通常你应该测试.blank?而不是.nil?因为某些表单元素可以发送空结果,例如选择类似于“全部”的选项作为默认值。
答案 2 :(得分:1)
你可以使用一些Ruby习语来获得更简洁的东西。
尝试这样的事情:(未经测试的代码!)
def index
@groups = Group.find :all, :conditions => [:city_id, :region_id, :country_id].inject {} do |conditions, name|
conditions[name] = params[name] unless params[name].blank?
conditions
end
end