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

Ruby on rails 什么';在没有HTTP重定向的情况下,从另一个控制器操作运行一个控制器操作的正确方法是什么?,ruby-on-rails,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"

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

我现在的情况是:

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
class OldController
这工作得很好,但它会发出HTTP重定向,速度很慢。我希望能够做同样的事情,但在相同的HTTP请求中

有没有干净的方法可以做到这一点


编辑:赏金将授予某人,他可以向我展示一种干净的方法,使控制器及其操作相对不受影响(重定向代码本身除外)。

与其跨操作调用代码,不如将代码提取到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

创建控制器类的实例:

@my_other_controller = MyOtherController.new
然后对其调用方法:

@my_other_controller.some_method(params[:id])
我更喜欢模块的想法,但这应该可以做到

还可以从另一个控制器整体传递参数:

@my_other_controller.params = params

我想你想要选项3,但让我们先看一些备选方案

选项1-将控制器选择逻辑推送到一个助手中,该助手将正确的链接插入到视图中。好处-控制器保持干净,缺点-如果决策逻辑取决于提交的值,这种方法将不起作用。如果URL被外部网站调用,那么这将不起作用

选项2-将逻辑推回到您的模型中。专业的-保持控制器清洁。缺点-如果你有很多sesson、params或render/redirect_到交互,那么它就不能正常工作

选项3保持在同一控制器内。我怀疑您试图用一些新功能替换一些现有功能,但仅在某些情况下。专业的-简单,有权访问您需要的一切。Cons-仅在使用同一控制器有意义时有效,即您与同一实体(如用户、地点或公司)合作

让我们看一个选项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
类链接控制器“新建管理员”
结束
def新用户
#所有的好东西-可以使用params、flash等
render:action=>“新用户”
结束
结束

如果两个控制器尝试执行相同的操作,则很有可能在一个模型中执行此操作。仔细看看您的设计,很抱歉,我不知道您在MVC方面的经验水平,请阅读瘦控制器技术:

如果问题是您需要另一个控制器来进行渲染,那么可能路线应该首先指向那里,而skinny controller技术仍然可以节省时间。

执行以下操作:

class OldController < ApplicationController
  def old_controller_action
    if should_use_new_controller
      new_controller_action
    end
    # rest of old and busted
  end
end
class OldController
还有新的控制器

class NewController < OldController
  def new_controller_action
    # new hotness
  end
end
class NewController
如果将控制器之间的公共代码提取到模块中对您不起作用,我将使用机架中间件。我没有看到在中间件中使用
ActiveRecord
的代码,但我不知道为什么不可能,因为人们使用了
Redis

否则,我认为您唯一的选择是使用类似(未测试,伪示例)的内容重新启动请求处理:

这类似于集成测试的实现方式。但是我不知道从
调用
到你点击一个控制器,所有的事情是否都是幂等的,并且可以像这样安全地重新运行。你可以通过追踪源代码来查看。但即使现在一切正常,它也有可能在rails或rack的任何未来版本中崩溃

使用中间件可以在请求运行之前拦截请求,从而避免这种情况。通过将代码提取到包含在这两个地方的通用模块中,您应该仍然能够与rails应用程序共享代码


老实说,我认为仅仅做普通控制器代码的分解这件简单的事情可能更干净,但是如果没有您的详细情况,很难知道,所以我想我会继续提出这个建议。

是的,我也想到了这个,尽管这不是一个非常令人兴奋的选择,从代码组织的角度来看,这实际上是可以的,因为它创建了从两个地方调用的内聚方法,这很容易测试,但效果不太好。很难在控制器的这个新实例中调用“render”方法。如果在原始控制器中调用render,则将丢失在被调用控制器中设置的所有变量。Jarrod-controller=sessioncontroller.new post controller.create如何在此create方法中传递参数。比如用户名和密码?
env['REQUEST_URI'] = new_controller_uri_with_your_params
call(env)