Is there a way I could pass an argument to a controller action call from middleware?
This is the action in controller code
# in my_controller.rb
#
def print_name(name)
render :text => "Hello, #{name}!"
end
Here's the code from my middleware that calls this action
# in middleware
#
def call(env)
env['action_controller.instance'].class.action(:print_name).call(env)
end
This of course raises ArgumentError
.
I'm unaware how can I pass an argument to action
call. Here's the source:
# 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
As you can see, it returns a rack endpoint from provided controller action. I see no way I could pass an argument here.
I ended up changing the controller dynamically with class_eval
and then calling the controller method from that proxy method.
# 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
This seems dirty and I would like to know of a better way. Thanks.
Rack middleware is a way to filter a request and response coming into your application. A middleware component sits between the client and the server, processing inbound requests and outbound responses, but it's more than interface that can be used to talk to web server.
Action Dispatch routes requests to controllers. Action Controller converts requests into responses. Action View is used by Action Controller to format those responses.
Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.
Rack is a gem to interface your framework to a Ruby application server such as Mongrel, Thin, Lighttpd, Passenger, WEBrick or Unicorn. An application server is a special type of web server that runs server applications, often in Ruby.
You don't want to put arguments on your action. Middleware should only interact with the request environment, not try to call into the controller directly.
You can pass the same value in the params hash:
# middleware
#
def call(env)
request = Rack::Request.new(env)
request['name'] = get_name
end
and read from the params hash in the controller:
# my_controller.rb
#
def print_name
render :text => "Hello, #{params['name']}!"
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With