这段代码感觉不对。我试图让我的控制器变瘦,我觉得控制器操作中有太多的逻辑。
组织此代码的更好方法是什么?
def search
where_obj = {:status => 1}
if params[:city].present?
where_obj.merge! :city => params[:city]
end
if params[:county].present?
where_obj.merge! :county => params[:county]
end
## THERE WILL BE MANY MORE IF STATEMENTS HERE DUE TO GROWING SEARCH FORM
@person = Person.where(where_obj)
end
随着搜索表单的增长,此控制器操作也会增长。如何保持控制器的瘦身?
怎么样:
def search
query = { :status => 1 }.merge(params.select { |k,_| [:city, :country].include?(k) })
@person = Person.where(query)
end
或者使用ActiveSupport
提供的slice
方法(在Rails中)的更简单的版本:
def search
query = { :status => 1 }.merge(params.slice(:city, :country))
@person = Person.where(query)
end
如果你要有一堆不同的参数有选择地包含,那么你可以像这样对它们进行分组:
def search
search_params = [:city, :country, :continent, ...]
query = { :status => 1 }.merge(params.slice(*search_params))
@person = Person.where(query)
end
(感谢@ajcodez指出在传递给slice
时需要对search_params
进行拼接。
def search
@person = Person.where({status: 1}.merge(params).select{|_, v| v.present?})
end
这是我的做法。您也可以将字段定义为常量。
FIELDS = [:city, :country]
def search
query_params = params.slice(*FIELDS).reject { |_,val| val.blank? }
query_params[:status] = 1
@person = Person.where query_params
end
请注意字段上的板片。Hash#slice: http://api.rubyonrails.org/v2.3.8/classes/ActiveSupport/CoreExtensions/Hash/Slice.html
# controller
def search
@person = PersonSearch.new(params).result
end
# lib/person_search.rb
class PersonSearch
attr_accessor :params
SUPPORTED_FIELDS = [:city, :country]
def initialize(params)
@params = params
end
def result
Person.where conditions
end
private
def conditions
conditions = default_conditions
SUPPORTED_FIELDS.each do |field|
conditions.merge!(field => params[field]) if params[field]
end
conditions
end
def default_conditions
{ :status => 1 }
end
end
不断增长的搜索表单?向SUPPORTED_FIELDS
添加更多属性。
优点:
+ 可扩展(甚至支持其他型号)
+ 可测试(即使大部分不会击中您的数据库)
+ 可重复使用
缺点:
- 代码稍微多一点