Rails: llamar a otra acción de controlador desde un controlador

118

Necesito llamar a la acción de creación en el controlador A, desde el controlador B.

La razón es que necesito redirigir de manera diferente cuando llamo desde el controlador B.

¿Se puede hacer en Rails?

ddayan
fuente
¿Estás hablando de acción POST o GET? Si GET puede simplemente redirigir a esa acción. Pero la razón de eso no está muy clara, ya que puede redirigir desde el controlador A a la URL que desee.
Voldy
posible duplicado de Llamar a un controlador desde otro
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

64

Puede usar una redirección a esa acción:

redirect_to your_controller_action_url

Más sobre: Guía de rieles

Para representar la nueva acción:

redirect_to your_controller_action_url and return
Spyros
fuente
5
Lo siento, pero ¿puede decirnos cuál es la diferencia entre la primera y la segunda línea? Creo que primero ejecutará las líneas restantes de código y luego las redireccionará. ¿Es eso correcto?
aks
Estoy pensando que tal vez el último ejemplo fue un error tipográfico y debería ser en renderlugar de redirect_to. ¿Qué dices, @Spyros?
Magne
1
Hola @spyros, el redirect_tono permite su uso post: :methody esto puede ser útil particularmente para redirigir a una createacción ya existente de otro controlador como @ddayan pidió la primera vez. Tengo una situación similar en la que, en alguna situación, debería crear otro objeto. Llamar a la otra createacción puede ser más SECO ..
SanjiBukai
53

Para usar un controlador de otro, haga esto:

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
fuente
18
Si quisiera que las devoluciones de llamada aún se ejecuten en controller_you_want, lo haríacontroller_you_want.process(:action_you_want)
Constantijn Schepens
3
¡Gracias! Esto es muy útil para situaciones en las que no desea redireccionar, solo necesita una solución rápida para adoptar una acción de un controlador a otro. Redirigir es realmente algo diferente. Además: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)parece funcionar para devolver JSON desde el otro controlador
Yourpalal
1
Gran respuesta, justo lo que estaba buscando. Una pregunta: ¿qué formato deberían tomar los parámetros de solicitud aquí? Supongo que viven debajo, controller_you_want.requestpero no pudieron hacer que este disparo pasara una instancia de hash o parámetros.
SRack el
No estoy seguro de lo que estás preguntando @SRack. La paramsestén disponibles para controller_you_wantajustando el requestde la tercera línea. ¿Es eso lo que estás preguntando?
Sammy Larbi
1
probado en rieles 5, para renderizarlo debería serrender html: controller_you_want.process(:action_you_want)
nazar kuliyev
41

La lógica que presenta no es MVC, entonces no es compatible con Rails.

  • Un controlador muestra una vista o redirecciona

  • Un método ejecuta código

A partir de estas consideraciones, le aconsejo que cree métodos en su controlador y los llame desde su acción.

Ejemplo:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Dicho esto, puede hacer exactamente lo mismo a través de diferentes controladores y convocar un método desde el controlador A mientras está en el controlador B.

El vocabulario es sumamente importante por eso insisto mucho.

apneadiving
fuente
Sé que no debería hacer eso, pero esto no es parte de mi aplicación, es solo para probar y evaluar mi aplicación.
ddayan
9
Me encanta ... separa el método del render y luego llama al método individual donde sea necesario. Solo una pregunta ... ¿cómo se get_variablepuede llamar ahora desde otro controlador?
FloatingRock
1
@FloatingRock acaba de notar su pregunta / comentario: tiene varias opciones: podría definirse en un ancestro común o podría incluir un mixin común
apneadiving
Me encanta la respuesta, no estoy seguro del fragmento de la oración final
Gerard Simpson
30

Puede usar url_forpara obtener la URL de un controlador y una acción y luego usar redirect_topara ir a esa URL.

redirect_to url_for(:controller => :controller_name, :action => :action_name)
Austin
fuente
1
el otro no pareció funcionar para mí, se ve mejor, pero ¿cómo pasamos los parámetros?
msanjay
3
@msanjay puede pasarlos como otros parámetros a url_for. Por ejemplo, redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2)dará como resultado /contorller_name/action_name?param1=val1&param2=val2. Ver los documentos
Ariel Allon
si trato de redirigir a un controlador raíz como "MyOtherController", desde un controlador como "Module :: MyController" ... se resolverá llamando a "module / MyOtherController" ... ¿alguna idea de cómo puedo llamar a la raíz?
ggez44
12

Esta es una mala práctica para llamar a otra acción del controlador.

Debieras

  1. duplicar esta acción en su controlador B, o
  2. envolverlo como un método modelo, que se compartirá con todos los controladores, o
  3. puede extender esta acción en el controlador A.

Mi opinión:

  1. El primer enfoque no es SECO, pero es mejor que pedir otra acción.
  2. El segundo enfoque es bueno y flexible.
  3. El tercer enfoque es el que solía hacer a menudo. Así que mostraré un pequeño ejemplo.

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

Entonces puede enviar a este redirect_toparámetro de acción , que puede ser cualquier ruta que desee.

fl00r
fuente
Hola, para el ajuste de la solución B como método de modelo, ¿cómo concluir si no hay ningún modelo? Estamos trabajando en un motor de búsqueda y nos gustaría llamar a las vistas de búsqueda en el motor de búsqueda de otros motores. No existe ningún modelo de datos para la acción de búsqueda.
user938363
@ user938363: tal vez las dos acciones representen la misma vista (incluso si esas acciones están en controladores diferentes). La llamada "render" en sí misma se duplicará, pero eso en sí mismo es solo una línea de duplicación, no tan mal. Si tiene mucha lógica que prepara el hash de los parámetros para pasar a la llamada de renderizado, entonces podría evitar duplicarlo moviéndolo a su propio archivo (tal vez un modelo /modelso una clase o módulo ordinario /lib). El único problema es que si su controlador se comunica con la vista a través de variables de instancia, tendría que arreglar esa duplicación de otra manera.
antinome
¿Qué sucede si tiene un UserController que crea un nuevo usuario (registro) y, en caso de éxito, le gustaría invocar un SessionsController y autenticar al usuario? En este caso, de una forma u otra invoca SessionsController. Tiene alguna idea sobre esto?
dipole_moment
¿Por qué es una mala práctica? ¿Cuál es el problema con la respuesta de Sammy Lambi?
vasilakisfil
7

¿Quizás la lógica podría extraerse en un ayudante? los ayudantes están disponibles para todas las clases y no transfieren el control. Puede verificar dentro de él, tal vez el nombre del controlador, para ver cómo se llama.

Michael Durrant
fuente
6

Composición al rescate!

Dada la razón, en lugar de invocar acciones entre controladores, uno debería diseñar controladores para separar partes compartidas y personalizadas del código. Esto ayudará a evitar tanto la duplicación de código como la ruptura del patrón MVC.

Aunque eso se puede hacer de varias maneras, usar preocupaciones ( composición ) es una buena práctica.

# 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

Espero que ayude.

Oleg Afanasyev
fuente
2

Puede llamar a otra acción dentro de una acción de la siguiente manera:

redirect_to action: 'action_name'

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

  def action2
  end
end
CódecPM
fuente
-6

Separe estas funciones de los controladores y colóquelas en el archivo de modelo. Luego incluya el archivo del modelo en su controlador.

Michale.Gaocl
fuente
Mala sugerencia. Arruinará las responsabilidades, apunta a tener MVC. Problemas con las llamadas de sesión / cookies en el modelo, etc.
Ain Tohvri