我希望能够根据查询参数和数据库中的数据的组合,从一个控制器操作有条件地调度到另一个控制器操作。
我现在所拥有的是:
class OldController < ApplicationController
def old_controller_action
if should_use_new_controller
new_params = params.dup
new_params[:controller] = "new_controller_action"
redirect_to new_params
return
end
# rest of old and busted
end
end
class NewController < ApplicationController
def new_controller_action
# new hotness
end
end
这很好用,但它会发出HTTP重定向,这很慢。我希望能够做同样的事情,但在同一个HTTP请求中。
有干净的方法吗?
编辑:赏金将转到可以向我展示干净方法的人,让控制器及其操作相对不受影响(除了重定向代码本身)。
答案 0 :(得分:13)
不是跨操作调用代码,而是将代码提取到lib /或其他内容,并从两个控制器调用该代码。
# lib/foo.rb
module Foo
def self.bar
# ...
end
end
# posts_controller
def index
Foo.bar
end
# things_controller
def index
Foo.bar
end
答案 1 :(得分:8)
创建控制器类的实例:
@my_other_controller = MyOtherController.new
然后调用方法:
@my_other_controller.some_method(params[:id])
我更喜欢模块的想法,但这应该可以解决问题。
答案 2 :(得分:1)
我怀疑你想要选项3,但我们首先考虑一些替代方案
选项1 - 将控制器选择逻辑推入帮助程序,将正确的链接插入到视图中。 Benifits - 控制器保持清洁,缺点 - 如果决策逻辑取决于提交的值,这种方法将无效。如果外部网站正在调用URL,则无法使用。
选项2 - 将逻辑推回到您的模型中。 Pro's - 保持控制器清洁。缺点 - 如果你有很多sesson,params或render / redirect_to交互,那么效果不好。
选项3 - 保持在同一个控制器内。我怀疑您正试图用一些新功能替换某些现有功能,但仅在某些情况下。 Pro's - 简单,可以访问您需要的一切。缺点 - 只有在使用相同的控制器时才有效,即您正在使用同一个实体,例如用户,地点或公司。
让我们看一下选项3的一个例子。我的链接控制器对管理员的行为完全不同于其他用户......
class LinksController < ApplicationController
#...
def new
#Check params and db values to make a choice here
admin? ? new_admin : new_user
end
#...
private
def new_admin
#All of the good stuff - can use params, flash, etc
render :action => 'new_admin'
end
def new_user
#All of the good stuff - can use params, flash, etc
render :action => 'new_user'
end
end
答案 3 :(得分:0)
如果两个控制器试图做同样的事情,那么这应该是模型的一个很好的机会。仔细看看你的设计 - 对不起,我不知道你对MVC的经验水平 - 阅读薄控制器技术:
http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model http://www.robbyonrails.com/articles/2007/06/19/put-your-controllers-on-a-diet-already http://andrzejonsoftware.blogspot.com/2008/07/mvc-how-to-write-controllers.html
如果问题是你需要另一个控制器进行渲染,那么路径应该指向那里开始,而且瘦的控制器技术仍然可以节省一天。
答案 4 :(得分:0)
如果将控制器之间的公共代码解压缩到模块中对你不起作用,我会使用Rack中间件。我没有看到在中间件中使用ActiveRecord
的代码,但我不知道为什么它不可能,因为人们使用Redis
之类的东西。
否则我认为你唯一的选择就是重新开始处理请求,例如(未经测试,伪示例):
env['REQUEST_URI'] = new_controller_uri_with_your_params
call(env)
这与集成测试的实现方式类似。但我不知道从call
到你控制器的所有内容是否都是幂等的,可以安全地重新运行。您可以浏览源并查看。但即使它现在没问题,它也可能会在未来版本的rails或rack中出现故障。
使用中间件可以避免这种情况,让您在请求运行之前拦截它。您仍然可以通过将代码提取到两个位置包含的常用模块来与rails应用程序共享代码。
老实说,我认为只是简单地将公共控制器代码分解出来可能更简洁,但是如果没有你的情况细节就很难知道,所以我想我会继续提出建议。
答案 5 :(得分:-1)
这样做:
class OldController < ApplicationController
def old_controller_action
if should_use_new_controller
new_controller_action
end
# rest of old and busted
end
end
和新控制器
class NewController < OldController
def new_controller_action
# new hotness
end
end