Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling a controller action with argument from rack middleware

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.

like image 503
shime Avatar asked Apr 09 '12 11:04

shime


People also ask

What is rack middleware?

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.

What is Actiondispatch?

Action Dispatch routes requests to controllers. Action Controller converts requests into responses. Action View is used by Action Controller to format those responses.

What is rack in ROR?

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.

What is rack gem?

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.


1 Answers

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
like image 90
Winfield Avatar answered Sep 18 '22 17:09

Winfield