Rails: appeler une autre action de contrôleur à partir d'un contrôleur


118

Je dois appeler l'action de création dans le contrôleur A, à partir du contrôleur B.

La raison en est que je dois rediriger différemment lorsque j'appelle du contrôleur B.

Cela peut-il être fait dans les rails?



Parlez-vous de l'action POST ou GET? Si GET vous pouvez simplement rediriger vers cette action. Mais la raison en n'est pas claire car vous pouvez rediriger du contrôleur A vers l'URL de votre choix.
Voldy

Réponses:


64

Vous pouvez utiliser une redirection vers cette action:

redirect_to your_controller_action_url

En savoir plus: Guide des rails

Pour simplement rendre la nouvelle action:

redirect_to your_controller_action_url and return

5
Je suis désolé mais pouvez-vous dire quelle est la différence entre la première ligne et la deuxième ligne? Je pense d'abord exécutera les lignes de code restantes, puis redirigera. Est-ce exact?
aks

Je pense que le dernier exemple était peut-être une faute de frappe et devrait l'être à la renderplace redirect_to. Que dites-vous, @Spyros?
Magne

1
Salut @spyros, le redirect_tone permet pas d'utiliser post: :methodet cela peut être utile notamment pour rediriger vers une createaction déjà existante d'un autre contrôleur comme @ddayan l'a demandé à la première fois. J'ai une situation similaire où, dans certaines situations, je devrais créer un autre objet. Appeler l'autre createaction peut être DRYer ..
SanjiBukai

53

Pour utiliser un contrôleur à partir d'un autre, procédez comme suit:

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
Si vous vouliez que les rappels soient toujours exécutés, controller_you_wantvous le feriezcontroller_you_want.process(:action_you_want)
Constantijn Schepens

3
Merci! Ceci est très utile dans les situations où vous ne souhaitez pas rediriger, vous avez juste besoin d'une solution rapide pour adopter une action d'un contrôleur à un autre. La redirection est vraiment quelque chose de différent. Aussi: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)semble fonctionner pour renvoyer JSON de l'autre contrôleur
Yourpalal

1
Excellente réponse, exactement ce que je cherchais. Une question - quel format les paramètres de demande devraient-ils prendre ici? Je suppose qu'ils vivent sous controller_you_want.requestmais n'ont pas pu obtenir ce tir en passant une instance de hachage ou de paramètres.
SRack

Je ne sais pas ce que vous demandez à @SRack. Le paramsdevenir disponible controller_you_wanten définissant le requestdans la 3ème ligne. C'est ce que vous demandez?
Sammy Larbi

1
essayé dans les rails 5, pour le rendu il devrait êtrerender html: controller_you_want.process(:action_you_want)
nazar kuliyev

41

La logique que vous présentez n'est pas compatible MVC, donc pas Rails.

  • Un contrôleur rend une vue ou une redirection

  • Une méthode exécute du code

A partir de ces considérations, je vous conseille de créer des méthodes dans votre contrôleur et de les appeler depuis votre action.

Exemple:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Cela dit, vous pouvez faire exactement la même chose avec différents contrôleurs et invoquer une méthode à partir du contrôleur A pendant que vous êtes dans le contrôleur B.

Le vocabulaire est extrêmement important c'est pourquoi j'insiste beaucoup.


Je sais que je ne devrais pas faire cela, mais cela ne fait pas partie de mon application, c'est juste pour tester et évaluer mon application.
ddayan

9
J'adore ... séparez la méthode du rendu, puis appelez la méthode individuelle si nécessaire. Juste une question ... comment peut-on get_variablemaintenant être appelé depuis un autre contrôleur?
FloatingRock

1
@FloatingRock vient de remarquer votre question / commentaire: vous avez plusieurs options: peut être défini dans l'ancêtre commun ou vous pouvez inclure un mixin commun
apneadiving le

J'adore la réponse, je ne suis pas sûr du fragment de phrase de fin
Gerard Simpson

30

Vous pouvez utiliser url_forpour obtenir l'URL d'un contrôleur et une action, puis utiliser redirect_topour accéder à cette URL.

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

1
l'autre ne semblait pas fonctionner pour moi, ça a l'air mieux, mais comment passer des paramètres?
msanjay

3
@msanjay vous pouvez les transmettre comme autres paramètres à url_for. Par exemple, cela redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2)aboutira /contorller_name/action_name?param1=val1&param2=val2. Voir la documentation
Ariel Allon

si j'essaye de rediriger vers un contrôleur racine comme "MyOtherController", à partir d'un contrôleur comme "Module :: MyController" .. il se résoudra à appeler "module / MyOtherController" .. une idée comment je peux appeler la racine?
ggez44

12

C'est une mauvaise pratique d'appeler une autre action de contrôleur.

Vous devriez

  1. dupliquez cette action dans votre contrôleur B, ou
  2. enveloppez-le comme une méthode modèle, qui sera partagée avec tous les contrôleurs, ou
  3. vous pouvez étendre cette action dans le contrôleur A.

Mon avis:

  1. La première approche n'est pas DRY mais c'est toujours mieux que d'appeler à une autre action.
  2. La deuxième approche est bonne et flexible.
  3. La troisième approche est ce que je faisais souvent. Je vais donc montrer un petit exemple.

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

Vous pouvez donc envoyer ce redirect_toparamètre d' action , qui peut être le chemin de votre choix.


Salut, pour la solution B wrap comme méthode de modèle, comment conclure s'il n'y a pas de modèle du tout? Nous travaillons sur un moteur de recherche et souhaitons appeler des vues de recherche dans le moteur de recherche à partir d'autres moteurs. Il n'existe aucun modèle de données pour l'action de recherche.
user938363

@ user938363 - Peut-être que les deux actions rendent toutes les deux la même vue (même si ces actions sont dans des contrôleurs différents). L'appel "render" lui-même sera dupliqué mais ce n'est en soi qu'une ligne de duplication - pas si mal. Si vous avez beaucoup de logique qui prépare le hachage des paramètres à passer à l'appel de rendu, vous pouvez éviter de le dupliquer en le déplaçant dans son propre fichier (peut-être un modèle dans /modelsou une classe ou un module ordinaire dans /lib). Le seul problème est que si votre contrôleur communique avec la vue via des variables d'instance - vous devrez corriger cette duplication d'une autre manière.
antinome

Que faire si vous disposez d'un UserController qui crée un nouvel utilisateur (enregistrement) et qu'en cas de succès, vous souhaitez invoquer un SessionsController et authentifier l'utilisateur? Dans ce cas, vous invoquez d'une manière ou d'une autre SessionsController. Des pensées à ce sujet?
dipole_moment

Pourquoi est-ce une mauvaise pratique? quel est le problème avec la réponse de Sammy Lambi?
vasilakisfil

7

Peut-être que la logique pourrait être extraite dans un assistant? les helpers sont disponibles pour toutes les classes et ne transfèrent pas le contrôle. Vous pouvez vérifier dedans, peut-être pour le nom du contrôleur, pour voir comment il a été appelé.


6

La composition à la rescousse!

Étant donné la raison, plutôt que d'appeler des actions entre les contrôleurs, il faut concevoir des contrôleurs pour séparer les parties partagées et personnalisées du code. Cela aidera à éviter à la fois la duplication de code et la rupture du modèle MVC.

Bien que cela puisse être fait de plusieurs façons, l'utilisation des préoccupations ( composition ) est une bonne pratique.

# 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

J'espère que cela pourra aider.


2

Vous pouvez appeler une autre action dans une action comme suit:

redirect_to action: 'nom_action'

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

  def action2
  end
end

-6

Séparez ces fonctions des contrôleurs et placez-les dans un fichier modèle. Incluez ensuite le fichier de modèle dans votre contrôleur.


Mauvaise suggestion. Va gâcher les responsabilités, pointez pour avoir MVC. Problèmes avec les appels de session / cookie dans le modèle, etc.
Ain Tohvri
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.