当用户使用索引操作时,我正在显示问题列表。我想过滤此列表,仅显示被拒绝的问题、仅附有图像的问题等。
你是怎样做的?您是否只需在索引操作中添加代码以检查不同的命名参数是否在请求参数哈希中并使用它们构建查询。
myurl.com/questions?status=approved&only_images=yes
还是有更好的方法?
当用户使用索引操作时,我正在显示问题列表。我想过滤此列表,仅显示被拒绝的问题、仅附有图像的问题等。
你是怎样做的?您是否只需在索引操作中添加代码以检查不同的命名参数是否在请求参数哈希中并使用它们构建查询。
myurl.com/questions?status=approved&only_images=yes
还是有更好的方法?
您可以使用has_scope优雅地执行此操作:
# Model
scope :status, proc {|status| where :status => status}
scope :only_images, ... # query to only include questions with images
# Controller
has_scope :status
has_scope :only_images, :type => boolean
def index
@questions = apply_scopes(Question).all
end
为了使您的控制器保持纤薄并避免意大利面条式代码,您可以尝试使用以下方式:
控制器:
def index
@questions = Question.filter(params.slice(:status, :only_images, ...) # you still can chain with .order, .paginate, etc
end
模型:
def self.filter(options)
options.delete_if { |k, v| v.blank? }
return self.scoped if options.nil?
options.inject(self) do |scope, (key, value)|
return scope if value.blank?
case key
when "status" # direct map
scope.scoped(:conditions => {key => value})
when "only_images"
scope.scoped(:conditions => {key => value=="yes" ? true : false})
#just some examples
when "some_field_max"
scope.scoped(:conditions => ["some_field <= ?", value])
when "some_field_min"
scope.scoped(:conditions => ["some_field >= ?", value])
else # unknown key (do nothing. You might also raise an error)
scope
end
end
end
所以,我认为在这种情况下,有些地方你需要编写代码才能做得很好;模型和控制器。
对于模型,您应该使用范围。
#Model
scope :rejected, lambda { where("accepted = false") }
scope :accepted lambda { where("accepted = true") }
scope :with_image # your query here
在控制器中,
def index
@questions = @questions.send(params[:search])
end
您可以从 UI 发送方法名称并将其直接传递给模型中的范围。此外,您可以通过再次从 UI 传递它来避免 .all 大小写的“if”条件。
但是由于这直接将模型代码暴露给查看,您应该使用 before_filter 在控制器中的私有方法中过滤来自视图的任何不需要的过滤器参数。