我试图处理一个有点复杂的查询。我已经阅读了一些关于如何处理这个问题的方法,但它们并不适用于此,因为它不像一个复杂的搜索表单(比如在vBulletin搜索帖子表单中),而是一个按类别'过滤的一组路线(未发行,流行,最新)和时间' (所有时间,上个月,上周,今天)
我意识到下面的代码非常糟糕。我的目标只是让它工作,然后重构。更不用说,它甚至没有真正起作用,因为它没有考虑到两种类型和时间,只是其中一种,但我想我会在这个线程中处理它。
另外,为了使这个SO代码粘贴更加清晰,我从每一行中排除了.page(params[:page]).per(30)
,但是它需要继续使用它们。
那么,有谁知道我会怎么做呢?我已经仔细考虑了一段时间而且有点难过
def index
case params[:category]
when "latest"
@books = Book.all.page(params[:page]).per(30)
when "downloads"
@books = Book.order('downloads DESC')
when "top100"
@books = Book.order('downloads DESC').limit(100)
when "unreleased"
@books = Book.unreleased
else
@books = Book.all.page(params[:page]).per(30)
end
case params[:time]
when "today"
@books = Book.days_old(1)
when "week"
@books = Book.days_old(7)
when "month"
@books = Book.days_old(30)
when "all-time"
@books = Book.all
else
@books = Book.all.page(params[:page]).per(30)
end
end
路线:
# Books
get 'book/:id', to: 'books#show', as: 'book'
resources :books, only: [:index] do
get ':category/:time(/:page)', action: 'index', on: :collection
end
答案 0 :(得分:7)
将所有查询作为范围移动到模型
class Book < ActiveRecord::Base
scope :downloads, -> { order('downloads DESC') }
scope :top100, -> { order('downloads DESC').limit(100) }
scope :unreleased, -> { unreleased }
scope :today, -> { days_old(1) }
scope :week, -> { days_old(7) }
scope :month, -> { days_old(30) }
scope :latest, -> { }
scope :all_time, -> { }
end
创建辅助方法以过滤参数并避免不匹配的数据
class BooksController < ApplicationController
private
def category_params
%w(downloads top100 unreleased).include?(params[:category]) ? params[:category].to_sym : nil
end
def time_params
%w(today week month latest all_time).include?(params[:time]) ? params[:time].to_sym : nil
end
end
通过应用与params同名的范围来删除case
语句
def index
query = Book.all
query = query.send(category_params) if category_params
query = query.send(time_params) if time_params
@books = query.page(params[:page]).per(30)
end
在四行,我们仍然在Sandi Metz' guidelines的范围内! :)
答案 1 :(得分:2)
在rails中,您可以“链接”查询,例如
Book.where(:released => true).where(:popular => true)
与
相同 Book.where(:released => true, popular => true)
您可以使用它来帮助您进行重构。以下是我的看法:
def index
# Start with all books, we are going to add other filters later
query = Book.scoped
# Lets handle the time filter first
query = query.where(['created_at > ?', start_date] if start_date
case params[:category]
when "latest"
query = query.order('created_at DESC')
when "downloads"
query = query.order('downloads DESC')
when "top100"
query = query.order('downloads DESC').limit(100)
when "unreleased"
query = query.where(:released => false)
end
# Finally, apply the paging
@books = query.page(params[:page]).per(30)
end
private
def start_date
case params[:time]
when "today"
1.day.ago
when "week"
7.days.ago
when "month"
1.month.ago
when "all-time"
nil
else
nil
end
end