2012-04-09 4 views
5

Gibt es eine Möglichkeit, ein Argument zu einem Controller-Aktion Anruf von Middleware übergeben? Aufruf einer Controller-Aktion mit Argument aus Rack-Middleware

Dies ist die Aktion in Controller-Code

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

Hier ist der Code von meiner Middleware, die diese Aktion ruft

# in middleware 
# 
def call(env) 
    env['action_controller.instance'].class.action(:print_name).call(env) 
end 

Dies natürlich ArgumentError wirft.

Ich bin mir nicht bewusst, wie ich ein Argument an action Anruf übergeben kann. Hier ist die Quelle:

# 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 

Wie Sie sehen können, gibt es einen Rack-Endpunkt von der bereitgestellten Controller-Aktion zurück. Ich sehe keine Möglichkeit, hier einen Streit zu führen.

Ich landete den Controller dynamisch mit class_eval ändern und dann die Controller-Methode von dieser Proxy-Methode aufrufen.

# 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 

Dies scheint schmutzig, und ich möchte einen besseren Weg kennen. Vielen Dank.

+1

Es muss doch ein besserer Ansatz sein, was auch immer du bist versuchen zu tun. Wenn Sie mehr Kontext für das bereitstellen könnten, was Sie letztendlich erreichen möchten, gibt es wahrscheinlich eine viel weniger hacky Lösung. –

+0

Ich versuche, zu einer bestimmten Controller-Aktion umzuleiten, nachdem die Ausnahme ausgelöst wurde. Im Grunde ist es ein [Fix] (https://github.com/airbrake/airbrake/commit/e13041bf9c69527b9bb34043617e52b6c7615657) für den Airbrake-Edelstein. Es war schwierig genug, das Beispiel des Aufrufs der Controller-Methode aus der Middleware zu finden. Danke für den Kommentar. – shime

Antwort

4

Sie wollen keine Argumente auf Ihre Aktion setzen. Middleware sollte nur mit der Anforderungsumgebung interagieren und nicht versuchen, den Controller direkt aufzurufen.

Sie können den gleichen Wert im params-Hash übergeben:

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

und aus dem params-Hash in der Steuerung gelesen:

# my_controller.rb 
# 
def print_name 
    render :text => "Hello, #{params['name']}!" 
end 
+0

Ja, ich habe bemerkt, dass es falsch ist. Es wurde wie folgt für Rails 2.x implementiert, da es eine 'rescue_action_in_public (exception)' in 'ActionController' definiert hatte und diese Methode Aliasing war. Ich habe versucht, das gleiche Verhalten für Schienen 3.x zu implementieren, ohne den Methodenaufruf zu ändern. danke für deine antwort though -> accept, upvote und bounty :) – shime

+0

Danke. Sie können mich gerne per E-Mail an winfield.peterson über gmail oder gchat schicken, um weiter zu sprechen. Sie können möglicherweise Ihre Ausnahmebehandlung/Berichterstattung in eine Hilfsklasse extrahieren und sie sowohl in der Middleware als auch in den Controllern verwenden. Wenn es Controller-spezifische Redirect-Logik oder andere Sachen hat, könnten Sie das in einen Block stecken? Gerne schließe ich den Loop auf eine Komplettlösung. – Winfield

Verwandte Themen