Schienen: Rufen Sie eine andere Controller-Aktion von einem Controller aus auf

118

Ich muss die Erstellungsaktion in Controller A von Controller B aus aufrufen.

Der Grund ist, dass ich anders umleiten muss, wenn ich von Controller B aus anrufe.

Kann es in Rails gemacht werden?

ddayan
quelle
Sprechen Sie über POST- oder GET-Aktionen? Wenn GET, können Sie einfach zu dieser Aktion umleiten. Der Grund dafür ist jedoch nicht ganz klar, da Sie von Controller A zu einer beliebigen URL umleiten können.
Voldy
Mögliches Duplikat des
Aufrufs

Antworten:

64

Sie können eine Umleitung zu dieser Aktion verwenden:

redirect_to your_controller_action_url

Mehr dazu: Rails Guide

So rendern Sie einfach die neue Aktion:

redirect_to your_controller_action_url and return
Spyros
quelle
5
Es tut mir leid, aber können Sie sagen, was der Unterschied zwischen der ersten und der zweiten Zeile ist? Ich denke, zuerst werden die verbleibenden Codezeilen ausgeführt und dann umgeleitet. Ist das korrekt?
Aks
Ich denke, vielleicht war das letzte Beispiel ein Tippfehler und sollte renderstattdessen sein redirect_to. Was sagst du, @Spyros?
Magne
1
Hallo @spyros, das redirect_toerlaubt nicht zu verwenden post: :methodund dies kann besonders nützlich sein, um zu einer bereits vorhandenen createAktion eines anderen Controllers umzuleiten, wie @ddayan beim ersten Mal gefragt hat. Ich habe eine ähnliche Situation, in der ich in einer bestimmten Situation ein anderes Objekt erstellen sollte. Das Aufrufen der anderen createAktion kann DRYer sein ..
SanjiBukai
53

Gehen Sie folgendermaßen vor, um einen Controller von einem anderen zu verwenden:

def action_that_calls_one_from_another_controller
  controller_you_want = ControllerYouWant.new
  controller_you_want.request = request
  controller_you_want.response = response
  controller_you_want.action_you_want
end
Sammy Larbi
quelle
18
Wenn Sie möchten, dass Rückrufe weiterhin ausgeführt werden controller_you_want, tun Sie diescontroller_you_want.process(:action_you_want)
Constantijn Schepens
3
Vielen Dank! Dies ist sehr hilfreich für Situationen, in denen Sie nicht umleiten möchten. Sie benötigen lediglich eine schnelle Lösung, um eine Aktion von einem Controller auf einen anderen zu übertragen. Das Umleiten ist wirklich etwas anderes. Außerdem: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)scheint zu funktionieren, um JSON vom anderen Controller zurückzugeben
Yourpalal
1
Tolle Antwort, genau das, wonach ich gesucht habe. Eine Frage - welches Format müssten Anforderungsparameter hier annehmen? Ich gehe davon aus, dass sie unter leben, controller_you_want.requestaber nicht in der Lage waren, diese Auslösung durch eine Hash- oder Parameterinstanz zu bringen.
SRack
Ich bin mir nicht sicher, was Sie @SRack fragen. Die paramswerden verfügbar controller_you_wantdurch Einstellen der requestin der 3. Zeile. Fragen Sie das?
Sammy Larbi
1
versucht in Schienen 5, für das Rendern sollte es seinrender html: controller_you_want.process(:action_you_want)
Nazar Kuliyev
41

Die von Ihnen präsentierte Logik ist nicht MVC, dann nicht Rails-kompatibel.

  • Ein Controller rendert eine Ansicht oder leitet um

  • Eine Methode führt Code aus

Aufgrund dieser Überlegungen empfehle ich Ihnen, Methoden in Ihrem Controller zu erstellen und diese aus Ihrer Aktion heraus aufzurufen.

Beispiel:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Das heißt, Sie können genau dasselbe über verschiedene Controller tun und eine Methode von Controller A aufrufen, während Sie sich in Controller B befinden.

Der Wortschatz ist extrem wichtig, deshalb bestehe ich sehr darauf.

apneadiving
quelle
Ich weiß, dass ich das nicht tun sollte, aber dies ist nicht Teil meiner Anwendung, sondern dient nur zum Testen und Bewerten meiner Anwendung.
Tag
9
Ich liebe es. Trennen Sie die Methode vom Rendering und rufen Sie bei Bedarf die einzelne Methode auf. Nur eine Frage .. wie kann get_variablejetzt von einem anderen Controller aufgerufen werden?
FloatingRock
1
@FloatingRock hat gerade Ihre Frage / Kommentar bemerkt: Sie haben mehrere Optionen: könnte in gemeinsamen Vorfahren definiert werden oder Sie könnten gemeinsame Mixin
einschließen
liebe die Antwort, unsicher über das nachfolgende Satzfragment
Gerard Simpson
30

Sie können verwenden url_for, um die URL für einen Controller und eine Aktion abzurufen und dann redirect_tozu dieser URL zu wechseln.

redirect_to url_for(:controller => :controller_name, :action => :action_name)
Austin
quelle
1
der andere schien bei mir nicht zu funktionieren, das sieht besser aus, aber wie übergeben wir Parameter?
Msanjay
3
@msanjay Sie können sie als andere Parameter an url_for übergeben. Zum Beispiel redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2)ergibt sich /contorller_name/action_name?param1=val1&param2=val2. Siehe die Dokumente
Ariel Allon
Wenn ich versuche, von einem Controller wie "Module :: MyController" zu einem Root-Controller wie "MyOtherController" umzuleiten, wird der Aufruf von "module / MyOtherController" aufgelöst. Gibt es eine Idee, wie ich den Root aufrufen kann?
Ggez44
12

Dies ist eine schlechte Praxis, um eine andere Controller-Aktion aufzurufen.

Du solltest

  1. Duplizieren Sie diese Aktion in Ihrem Controller B oder
  2. Wrap es als Modellmethode, die für alle Controller freigegeben wird, oder
  3. Sie können diese Aktion in Controller A erweitern.

Meine Meinung:

  1. Der erste Ansatz ist nicht trocken, aber immer noch besser, als eine andere Aktion zu fordern.
  2. Der zweite Ansatz ist gut und flexibel.
  3. Der dritte Ansatz ist der, den ich oft gemacht habe. Also werde ich ein kleines Beispiel zeigen.

    def create
      @my_obj = MyModel.new(params[:my_model])
      if @my_obj.save
        redirect_to params[:redirect_to] || some_default_path
       end
    end

Sie können also an diesen Aktionsparameter redirect_tosenden, der ein beliebiger Pfad sein kann.

fl00r
quelle
Hallo, für Lösung B-Wrap als Modellmethode, wie wird ein Wrap durchgeführt, wenn überhaupt kein Modell vorhanden ist? Wir arbeiten an einer Suchmaschine und möchten Suchansichten in Suchmaschinen von anderen Suchmaschinen aus aufrufen. Es gibt überhaupt kein Datenmodell für die Suchaktion.
user938363
@ user938363 - Möglicherweise lassen beide Aktionen dieselbe Ansicht rendern (auch wenn sich diese Aktionen auf verschiedenen Controllern befinden). Der "Render" -Aufruf selbst wird dupliziert, aber das ist an sich nur eine Duplizierungszeile - nicht so schlimm. Wenn Sie über eine Menge Logik verfügen, die den Hash von Parametern für die Übergabe an den Renderaufruf vorbereitet, können Sie das Duplizieren vermeiden, indem Sie ihn in eine eigene Datei verschieben (möglicherweise ein Modell in /modelsoder eine gewöhnliche Klasse oder ein Modul in /lib). Das einzige Problem besteht darin, dass Ihr Controller über Instanzvariablen mit der Ansicht kommuniziert. Sie müssen diese Duplizierung auf andere Weise beheben.
Antinom
Was ist, wenn Sie einen UserController haben, der einen neuen Benutzer erstellt (Registrierung), und bei Erfolg einen SessionsController aufrufen und den Benutzer authentifizieren möchten? In diesem Fall rufen Sie auf die eine oder andere Weise SessionsController auf. Irgendwelche Gedanken dazu?
dipole_moment
Warum ist es eine schlechte Praxis? Was ist das Problem mit Sammy Lambi Antwort?
Vasilakisfil
7

Vielleicht könnte die Logik in einen Helfer extrahiert werden? Helfer stehen allen Klassen zur Verfügung und übertragen keine Kontrolle. Sie können darin nach dem Namen des Controllers suchen, um zu sehen, wie er aufgerufen wurde.

Michael Durrant
quelle
6

Zusammensetzung zur Rettung!

Aus diesem Grund sollte man Controller so gestalten, dass sie gemeinsam genutzte und benutzerdefinierte Teile des Codes trennen, anstatt Aktionen über Controller hinweg aufzurufen. Dies hilft, sowohl das Duplizieren von Code als auch das Brechen des MVC-Musters zu vermeiden.

Obwohl dies auf verschiedene Arten geschehen kann, ist die Verwendung von Bedenken ( Zusammensetzung ) eine gute Praxis.

# controllers/a_controller.rb
class AController < ApplicationController
  include Createable

  private def redirect_url
    'one/url'
  end
end

# controllers/b_controller.rb
class BController < ApplicationController
  include Createable

  private def redirect_url
    'another/url'
  end
end

# controllers/concerns/createable.rb
module Createable
  def create
    do_usefull_things
    redirect_to redirect_url
  end
end

Hoffentlich hilft das.

Oleg Afanasyev
quelle
2

Sie können eine andere Aktion innerhalb einer Aktion wie folgt aufrufen:

redirect_to action: 'action_name'

class MyController < ApplicationController
  def action1
   redirect_to action: 'action2'
  end

  def action2
  end
end
CodecPM
quelle
-6

Trennen Sie diese Funktionen von den Controllern und fügen Sie sie in die Modelldatei ein. Fügen Sie dann die Modelldatei in Ihren Controller ein.

Michale.Gaocl
quelle
Schlechter Vorschlag. Wird Verantwortlichkeiten durcheinander bringen, darauf hinweisen, MVC zu haben. Probleme mit Sitzungs- / Cookie-Aufrufen im Modell usw.
Ain Tohvri