Rails: chiama un'altra azione del controller da un controller


118

Devo chiamare l'azione di creazione nel controller A, dal controller B.

Il motivo è che devo reindirizzare in modo diverso quando chiamo dal controller B.

Può essere fatto in Rails?



Stai parlando di azione POST o GET? Se GET puoi semplicemente reindirizzare a quell'azione. Ma la ragione di ciò non è abbastanza chiara in quanto puoi reindirizzare dal controller A a qualsiasi URL tu voglia.
— Voldy

Risposte:


64

Puoi utilizzare un reindirizzamento a tale azione:

redirect_to your_controller_action_url

Altro su: Rails Guide

Per eseguire solo il rendering della nuova azione:

redirect_to your_controller_action_url and return

5
Mi dispiace ma puoi dire qual è la differenza tra la prima e la seconda riga? Penso che prima eseguirà le restanti righe di codice e quindi reindirizzerà. È corretto?
— risponde il

Penso che forse l'ultimo esempio sia stato un errore di battitura e dovrebbe essere renderinvece di redirect_to. Che ne dici, @Spyros?
— Magne

1
Ciao @spyros, il redirect_tonon permette l'uso post: :methode questo può essere utile in particolare per reindirizzare a un'azione già esistente createdi un altro controller come @ddayan ha chiesto la prima volta. Ho una situazione simile in cui in qualche situazione dovrei creare un altro oggetto. Chiamare l'altra createazione può essere DRYer ..
— SanjiBukai

53

Per utilizzare un controller da un altro, procedi come segue:

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

18
Se volessi che i callback vengano ancora eseguiti controller_you_want, lo faresticontroller_you_want.process(:action_you_want)
— Constantijn Schepens

3
Grazie! Questo è molto utile per le situazioni in cui non vuoi reindirizzare, hai solo bisogno di una soluzione rapida per adottare un'azione da un controller a un altro. Il reindirizzamento è davvero qualcosa di diverso. Inoltre: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)sembra funzionare per restituire JSON dall'altro controller
— Yourpalal

1
Ottima risposta, proprio quello che stavo cercando. Una domanda: quale formato dovrebbero avere i parametri di richiesta qui? Presumo che vivano sotto controller_you_want.requestma non sono stati in grado di ottenere questo fuoco passando un'istanza di hash o parametri.
— Ritorno

Non sono sicuro di cosa stai chiedendo @SRack. Il paramsdiventano disposizione controller_you_wantimpostando l' requestnel 3 ° riga. È quello che stai chiedendo?
— Sammy Larbi

1
provato in rails 5, per renderlo dovrebbe essererender html: controller_you_want.process(:action_you_want)
— nazar kuliyev

41

La logica che presenti non è MVC, quindi non è compatibile con Rails.

  • Un controller esegue il rendering di una vista o un reindirizzamento

  • Un metodo esegue il codice

Da queste considerazioni, ti consiglio di creare metodi nel tuo controller e di richiamarli dalla tua azione.

Esempio:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Detto questo, puoi fare esattamente lo stesso attraverso controller diversi ed evocare un metodo dal controller A mentre sei nel controller B.

Il vocabolario è estremamente importante, ecco perché insisto molto.


So che non dovrei farlo, ma questo non fa parte della mia applicazione è solo per testare e valutare la mia applicazione.
— giorno

9
Lo adoro .. separa il metodo dal rendering, quindi chiama il metodo individuale dove necessario. Solo una domanda .. come si può get_variableora essere richiamati da un altro controller?
— FloatingRock

1
@FloatingRock ha appena notato la tua domanda / commento: hai diverse opzioni: potrebbe essere definito in antenato comune o potresti includere un mixin comune
— apneadiving

amo la risposta, incerto sul frammento di frase finale
— Gerard Simpson

30

È possibile utilizzare url_forper ottenere l'URL di un controller e un'azione e quindi utilizzare per accedere redirect_toa tale URL.

redirect_to url_for(:controller => :controller_name, :action => :action_name)

1
l'altro non sembra funzionare per me, sembra migliore, ma come passiamo i parametri?
— msanjay

3
@msanjay puoi passarli come altri parametri a url_for. Ad esempio redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2)risulterà in /contorller_name/action_name?param1=val1&param2=val2. Vedi i documenti
— Ariel Allon

se provo a redirect_to un controller di root come "MyOtherController", da un controller come "Module :: MyController" .. si risolverà a chiamare "module / MyOtherController" .. qualche idea di come posso chiamare il root?
— ggez44

12

È una cattiva pratica chiamare un'altra azione del controller.

Dovresti

  1. duplica questa azione nel controller B o
  2. avvolgerlo come metodo modello, che verrà condiviso con tutti i controller, o
  3. puoi estendere questa azione nel controller A.

La mia opinione:

  1. Il primo approccio non è A SECCO ma è comunque meglio che richiedere un'altra azione.
  2. Il secondo approccio è buono e flessibile.
  3. Il terzo approccio è quello che facevo spesso. Quindi mostrerò un piccolo esempio.

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

Quindi puoi inviare a questo redirect_toparametro di azione , che può essere qualsiasi percorso tu voglia.


Salve, per la soluzione B avvolgere come metodo di modello, come concludere se non c'è alcun modello? Stiamo lavorando su un motore di ricerca e vorremmo richiamare le visualizzazioni di ricerca nel motore di ricerca da altri motori. Non esiste alcun modello di dati per l'azione di ricerca.
— user938363

@ user938363 - Forse le due azioni renderanno entrambe la stessa vista (anche se queste azioni si trovano in controller diversi). La stessa chiamata "render" verrà duplicata, ma di per sé è solo una riga di duplicazione - non così male. Se hai molta logica che prepara l'hash dei parametri da passare alla chiamata di rendering, potresti evitare di duplicarlo spostandolo nel proprio file (forse un modello in /modelso una normale classe o modulo in /lib). L'unico problema è che se il tuo controller comunica con la vista tramite variabili di istanza, dovresti correggere la duplicazione in un altro modo.
— antinome

Cosa succede se si dispone di un UserController che crea un nuovo utente (registrazione) e in caso di successo desideri richiamare un SessionsController e autenticare l'utente? In questo caso, in un modo o nell'altro richiami SessionsController. Qualche idea su questo?
— dipole_moment

Perché è una cattiva pratica? qual è il problema con la risposta di Sammy Lambi?
— vasilakisfil

7

Forse la logica potrebbe essere estratta in un aiutante? gli helper sono disponibili per tutte le classi e non trasferiscono il controllo. Puoi controllare al suo interno, forse per il nome del controller, per vedere come è stato chiamato.


6

Composizione in soccorso!

Data la ragione, piuttosto che invocare azioni tra i controller, è necessario progettare i controller per separare le parti condivise e personalizzate del codice. Ciò contribuirà a evitare entrambi: la duplicazione del codice e l'interruzione del pattern MVC.

Sebbene ciò possa essere fatto in diversi modi, utilizzare le preoccupazioni ( composizione ) è una buona pratica.

# 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

Spero che aiuti.


2

Puoi chiamare un'altra azione all'interno di un'azione come segue:

redirect_to action: "action_name"

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

  def action2
  end
end

-6

Separare queste funzioni dai controller e inserirle nel file modello. Quindi includere il file del modello nel controller.


Cattivo suggerimento. Incasinerà le responsabilità, punta ad avere MVC. Problemi con chiamate di sessione / cookie nel modello, ecc.
— Ain Tohvri
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.