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.