我有一个看起来非常像这样的索引方法:
def index
if params[:brand]
@users = User.includes(:brand).where(brand_id: params[:brand]).order("#{sort_column} #{sort_direction}").page(params[:page]).per(10)
elsif params[:search]
@user = User.includes(:brand).find_by_client_code(params[:search])
redirect_to edit_user_path(@user)
elsif params[:page] == 'all'
@users = User.includes(:brand).order("#{sort_column} #{sort_direction}").all
elsif params[:state]
@users = User.includes(:brand).where(state: params[:state]).page(params[:page]).per(10)
else
@users = User.includes(:brand).order("#{sort_column} #{sort_direction}").page(params[:page]).per(10)
end
end
我知道,这很混乱但是很有效。现在我正在尝试重构它,我无法弄清楚将它拆分成较小的集合的最佳方法,而不会使我的路线复杂化。
def index
[:brand, :page, :search, :state].each do |param|
if params[:page] == 'all'
@users = User.includes(:brand).order(column + ' ' + direction)
elsif params.key?(param)
param
else
@users = User.includes(:brand).order(column + ' ' + direction)
.page(params[:page]).per(10)
end
end
end
def brand
@users = User.includes(:brand).where('brand_id in (?)', params[:brand])
.order(column + ' ' + direction).page(params[:page]).per(10)
end
def state
@users = User.includes(:brand).where(state: params[:state])
.page(params[:page]).per(10)
end
def search
@user = User.includes(:brand).find_by_client_code(params[:search])
redirect_to edit_user_path(@user)
end
以上不起作用,但你明白了。有谁知道处理这种情况的好方法?欢呼声。
答案 0 :(得分:1)
我可能会这样做 -
首先,更新此代码,您已将sort_column
和sort_direction
方法定义为默认值:
def sort_column
colum_name = params[:colum_name]
colum_name ||= 'id'
end
def sort_direction
direction = params[:direction]
direction ||= 'ASC'
end
添加一个新方法,让per_page
(在您拥有sort_column
和sort_direction
的同一位置)来自params或默认来自User
class:
def per_page
per = params[:per_page]
per ||= User.per_page
end
app / models / user.rb 中的:
scope :with_brand_id, ->(id) { where(brand_id: id) }
scope :with_state, ->(state) { where(state: state) }
scope :order_with, ->(column_name, direction) { order("#{sort_column} #{sort_direction}") }
# never use/avoid magic numbers in your application at multiple places as they gets unmanageable as your application grows
# single place to manage your per page entries for users.
def self.per_page
10
end
# easy to use key:value based arguments since you're using Ruby 2, cheers!
def self.fetch_with_brand(brand: nil, state: nil, page: nil, sort_column: 'id', sort_direction: 'ASC', per_page: User.per_page)
user_scope, pagination_scope_applies = if brand.present?
[self.with_brand_id(brand), true]
elsif state.present?
[self.with_state(state), true]
else
[self.scoped, (page != 'all')]
end
user_scope.merge(pagination_scope(page, per_page)) if pagination_scope_applies
user_scope.includes(:brand).order_with(sort_column, sort_direction)
end
# since I am not sure about your implementation of `page` and `per` methods, I'd create a class method, otherwise you can create a `scope` for this, too
def self.pagination_scope(page_number, per_page)
self.page(page_number).per(per_page)
end
您是否在上述代码中找到了行[self.scoped, (page != 'all')]
?此处self.scoped
等于self.all
(评估时),但我们必须使用scoped
代替all
,因为在Rails 3中它提供了数组,而在Rails 4中它将是一个 ActiveRecord :: Relation 对象,因此如果你在Rails 4上,你可以使用self.all
。注意:scoped
是在Rails 4中弃用,而不是all
。
另外,我想在这里指出一个问题。在您的代码中,您优先考虑params[:page] == 'all'
条件,然后优先考虑params[:search]
。在我上面提到的代码中,优先考虑search
然后优先考虑page
,但是你明白了,对吗?
现在,让我们在控制器中添加用户特定的params方法:
def user_params
params.slice(:brand, :page, :state).merge!({sort_column: sort_column, sort_direction: sort_direction, per_page: per_page })
end
但是,在Rails 4中,使用强参数更容易,例如:params.require(:user).permit(:search,..)
等。
现在,您的控制器的索引方法可能如下所示:
def index
if params[:search].present?
@user = User.find_by_client_code(params[:search])
redirect_to edit_user_path(@user)
else
@users = User.fetch_with_brand(user_params)
end
end
如果您倾向于将用户重定向到更多地方的编辑页面,您可以进一步重构:
before_filter :redirect_to_edit, only: [:index, :some_other_method_name]
def index
@users = User.fetch_with_brand(user_params)
end
def redirect_to_edit
if params[:search].present?
@user = User.find_by_client_code(params[:search])
redirect_to edit_user_path(@user)
end
end
您现在已经拥有了瘦控制器。