在没有HTTP重定向的情况下,从另一个控制器操作运行一个控制器操作的正确方法是什么?

时间:2009-04-30 20:55:31

标签: ruby-on-rails

我希望能够根据查询参数和数据库中的数据的组合,从一个控制器操作有条件地调度到另一个控制器操作。

我现在所拥有的是:

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请求中。

有干净的方法吗?

编辑:赏金将转到可以向我展示干净方法的人,让控制器及其操作相对不受影响(除了重定向代码本身)。

6 个答案:

答案 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