我一直在重构我的模型和控制器,以便删除代码重复,到目前为止它似乎都是极好的奶油味。目前我有两个控制器常用的代码,如下所示:
def process_filters
# Filter hash we're going to pass to the model
filter_to_use = {}
# To process filters, we first query the model to find out what filters
# we should be looking for, as the model knows what we can filter.
Iso.available_filters.each do |filter|
# We should have our array with our filter listing.
# Check the purchase order model for a description
filter_name = filter[0][:filter_name]
# Filters are stored in a session variable, this way filters survive
# page reloads, etc. First thing we do, is set the session if new filters
# have been set for the filter.
session_name = session_filter_name( filter_name )
if params[session_name]
if params[session_name] == 'All'
session[session_name] = nil
else
session[session_name] = params[session_name]
filter_to_use[filter_name] = params[session_name]
end
elsif session[session_name]
# If params aren't read, we still need to filter based off the users
# session
filter_to_use[filter_name] = session[session_name]
end
end
# Just using this variable for now until I can refactor the helper code
# so that this is passed in.
@current_filter_values = filter_to_use
filter_to_use[:page] = @current_page
@isos = Iso.find_filtered( filter_to_use )
if @isos.out_of_bounds?
filter_to_use[:page] = session[:previous_page] = @current_page = 1
@isos = Iso.find_filtered( filter_to_use )
end
end
现在这个代码与另一个控制器中的代码完全相同,除了模型引用(在本例中为Iso)。有没有我可以使该模型参考动态?
基本上我想将Iso引用(包括@iso变量)替换为基于controller.controller_name或类似的东西。
答案 0 :(得分:2)
您可以将此代码移动到模块中,将此模块混合到您需要的所有控制器中,并使用模块内部的self.class变量来确定具体的控制器名称。使用此名称,您可以使用标准字符串函数(例如,大写)和Kernel.const_get函数来按类名称获取类。
答案 1 :(得分:2)
好的,这就是我最终的结果。我决不是Ruby / Rails的大师,但它对我有用,所以如果他们尝试类似的东西,它可能会指向一个正确方向的人:
module Filtered
module Controller
module InstanceMethods
def process_filters
# Filter hash we're going to pass to the model
filter_to_use = {}
# To process filters, we first query the model to find out what filters
# we should be looking for, as the model knows what we can filter.
Kernel.const_get(
self.controller_name.singularize.camelize ).available_filters.each do |filter|
# We should have our array with our filter listing.
# Check the purchase order model for a description
filter_name = filter[0][:filter_name]
# Filters are stored in a session variable, this way filters survive
# page reloads, etc. First thing we do, is set the session if new filters
# have been set for the filter.
session_name = session_filter_name( filter_name )
if params[session_name]
if params[session_name] == 'All'
session[session_name] = nil
else
session[session_name] = params[session_name]
filter_to_use[filter_name] = params[session_name]
end
elsif session[session_name]
# If params aren't read, we still need to filter based off the users
# session
filter_to_use[filter_name] = session[session_name]
end
end
# Just using this variable for now until I can refactor the helper code
# so that this is passed in.
self.instance_variable_set( '@current_filter_values', filter_to_use )
filter_to_use[:page] = self.instance_variable_get( '@current_page' )
self.instance_variable_set( "@#{self.controller_name}",
Kernel.const_get( self.controller_name.singularize.camelize ).find_filtered(
filter_to_use ) )
if self.instance_variable_get( "@#{self.controller_name}" ).out_of_bounds?
filter_to_use[:page] = session[:previous_page] = 1
self.instance_variable_set( "@#{self.controller_name}",
Kernel.const_get( self.controller_name.singularize.camelize ).find_filtered(
filter_to_use ) )
end
end
private
# Quick helper function for generating session variable names
def session_filter_name( name )
"#{self.controller_name}_#{name}_filter".to_sym
end
end
end
end
我通过插件,init.rb文件将它包含在我的所有控制器中,如下所示:
# Include hook for controllers
ActionController::Base.class_eval do
include Filtered::Controller::InstanceMethods
end