使用来自机架中间件的参数调用控制器操作

shi*_*ime 5 ruby rack ruby-on-rails

有没有办法可以将参数传递给中间件的控制器动作调用?

这是控制器代码中的操作

# in my_controller.rb
# 
def print_name(name)
    render :text => "Hello, #{name}!"
end
Run Code Online (Sandbox Code Playgroud)

这是我的中间件中调用此操作的代码

# in middleware
#
def call(env)
  env['action_controller.instance'].class.action(:print_name).call(env)
end
Run Code Online (Sandbox Code Playgroud)

这当然会提高ArgumentError.

我不知道如何传递一个参数来action调用.这是来源:

# in action_pack/lib/action_controller/metal.rb
#
def self.action(name, klass = ActionDispatch::Request)
      middleware_stack.build(name.to_s) do |env|
        new.dispatch(name, klass.new(env))
      end
end
Run Code Online (Sandbox Code Playgroud)

如您所见,它从提供的控制器操作返回机架端点.我认为我无法在这里传递论据.

我最终动态更改控制器class_eval,然后从该代理方法调用控制器方法.

# in middleware
#
def define_proxy_method(klass)
      klass.class_eval do
            def call_the_real_method
              print_name(request.env['fake_attribute'])
            end
      end
 end

def call(env)
  define_proxy_method(env['action_controller.instance'].class)
  env['fake_attrbute'] = "Yukihiro"
  env['action_controller.instance'].class.action(:call_the_real_method).call(env)
end
Run Code Online (Sandbox Code Playgroud)

这看起来很脏,我想知道更好的方法.谢谢.

Win*_*eld 5

你不想对你的行为提出争论。中间件应该只与请求环境交互,而不是尝试直接调用控制器。

您可以在 params 哈希中传递相同的值:

# middleware
#
def call(env)
  request = Rack::Request.new(env)
  request['name'] = get_name
end
Run Code Online (Sandbox Code Playgroud)

并从控制器中的 params 哈希读取:

# my_controller.rb
# 
def print_name
    render :text => "Hello, #{params['name']}!"
end
Run Code Online (Sandbox Code Playgroud)