Rails: chame outra ação do controlador de um controlador

118

Preciso chamar a ação de criação no controlador A, do controlador B.

O motivo é que preciso redirecionar de maneira diferente quando estou ligando do controlador B.

Isso pode ser feito no Rails?

ddayan
fonte
Você está falando sobre a ação POST ou GET? Se GET, você pode simplesmente redirecionar para essa ação. Mas o motivo para isso não é totalmente claro, pois você pode redirecionar do controlador A para qualquer url que desejar.
Voldy
possível duplicata de Chamando um controlador de outro
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

64

Você pode usar um redirecionamento para essa ação:

redirect_to your_controller_action_url

Mais em: Guia Rails

Para apenas renderizar a nova ação:

redirect_to your_controller_action_url and return
Spyros
fonte
5
Sinto muito, mas você pode dizer qual é a diferença entre a primeira linha e a segunda linha? Acho que primeiro executarei as linhas de código restantes e depois redirecionarei. Isso está correto?
aks de
Estou pensando que talvez o último exemplo tenha sido um erro de digitação e deveria ser em rendervez de redirect_to. O que você acha, @Spyros?
Magne
1
Olá @spyros, o redirect_tonão permite usar post: :methode isso pode ser útil principalmente para redirecionar para uma createação já existente de outro controlador como @ddayan perguntou na primeira vez. Tenho uma situação semelhante em que, em alguma situação, devo criar outro objeto. Chamar a outra createação pode ser mais SECO ..
SanjiBukai
53

Para usar um controlador de outro, faça o seguinte:

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
fonte
18
Se você quiser que os retornos de chamada ainda sejam executados, controller_you_wantvocê fariacontroller_you_want.process(:action_you_want)
Constantijn Schepens
3
Obrigado! Isso é muito útil para situações em que você não deseja redirecionar, você só precisa de uma solução rápida para adotar uma ação de um controlador para outro. Redirecionar é realmente algo diferente. Além disso: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)parece funcionar para retornar JSON do outro controlador
Yourpalal
1
Ótima resposta, exatamente o que eu estava procurando. Uma pergunta - qual formato os parâmetros de solicitação precisam seguir aqui? Presumo que eles vivam sob, controller_you_want.requestmas não foi possível obter esse disparo passando uma instância de hash ou de parâmetros.
SRack
Não tenho certeza do que você está perguntando a @SRack. Torne- paramsse disponível ao controller_you_wantdefinir o requestna 3ª linha. É isso que você está perguntando?
Sammy Larbi
1
tentado no trilho 5, para renderizá-lo deve serrender html: controller_you_want.process(:action_you_want)
nazar kuliyev
41

A lógica que você apresenta não é compatível com MVC, e nem com Rails.

  • Um controlador renderiza uma visualização ou redireciona

  • Um método executa código

A partir dessas considerações, aconselho você a criar métodos em seu controlador e chamá-los de sua ação.

Exemplo:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Dito isso, você pode fazer exatamente o mesmo por meio de controladores diferentes e invocar um método do controlador A enquanto estiver no controlador B.

O vocabulário é extremamente importante, por isso insisto muito.

apneadiving
fonte
Eu sei que não deveria fazer isso, mas isso não faz parte do meu aplicativo, é apenas para testar e avaliar meu aplicativo.
ddayan
9
Adorei ... separe o método do render e chame o método individual quando necessário. Só uma pergunta .. como get_variableagora pode ser chamado de outro controlador?
FloatingRock
1
@FloatingRock acabou de notar sua pergunta / comentário: você tem várias opções: pode ser definido como ancestral comum ou pode incluir
mixin
adorei a resposta, não tenho certeza sobre o fragmento de frase final
Gerard Simpson
30

Você pode usar url_forpara obter a URL de um controlador e ação e, em seguida, usar redirect_topara ir para essa URL.

redirect_to url_for(:controller => :controller_name, :action => :action_name)
Austin
fonte
1
o outro não pareceu funcionar para mim, parece melhor, mas como passamos os parâmetros?
msanjay
3
@msanjay você pode passá-los como outros parâmetros para url_for. Por exemplo redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2), resultará em /contorller_name/action_name?param1=val1&param2=val2. Veja os documentos
Ariel Allon
se eu tentar redirect_to um controlador root como "MyOtherController", de um controlador como "Module :: MyController" .. ele resolverá chamar "module / MyOtherController" .. alguma idéia de como posso chamar o root?
ggez44
12

Esta é uma prática inadequada para chamar outra ação do controlador.

Você deve

  1. duplique esta ação em seu controlador B, ou
  2. envolva-o como um método de modelo, que será compartilhado com todos os controladores, ou
  3. você pode estender esta ação no controlador A.

Minha opinião:

  1. A primeira abordagem não é SECA, mas ainda é melhor do que solicitar outra ação.
  2. A segunda abordagem é boa e flexível.
  3. A terceira abordagem é o que eu costumava fazer com frequência. Então, vou mostrar um pequeno exemplo.

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

Portanto, você pode enviar para este redirect_toparâmetro de ação , que pode ser qualquer caminho que desejar.

fl00r
fonte
Olá, para a solução B embrulhar como um método de modelo, como finalizar se não houver nenhum modelo? Estamos trabalhando em um mecanismo de pesquisa e gostaríamos de chamar visualizações de pesquisa em mecanismos de pesquisa de outros mecanismos. Não existe nenhum modelo de dados para a ação de pesquisa.
user938363
@ user938363 - Talvez as duas ações renderizem a mesma visualização (mesmo se essas ações estiverem em controladores diferentes). A chamada "render" em si será duplicada, mas isso em si é apenas uma linha de duplicação - não tão ruim. Se você tiver muita lógica que prepara o hash de parâmetros para passar para a chamada de renderização, poderá evitar a duplicação movendo-o para seu próprio arquivo (talvez um modelo /modelsou uma classe ou módulo comum /lib). O único problema é se o seu controlador se comunica com o modo de exibição por meio de variáveis ​​de instância - você teria que consertar essa duplicação de outra maneira.
antinome
E se você tiver um UserController que cria um novo usuário (registro) e, em caso de sucesso, gostaria de invocar um SessionsController e autenticar o usuário? Neste caso, você de uma forma ou de outra invoca SessionsController. Alguma opinião sobre isso?
dipole_moment
Por que é uma prática ruim? qual é o problema com a resposta de Sammy Lambi?
vasilakisfil
7

Talvez a lógica pudesse ser extraída de um ajudante? os ajudantes estão disponíveis para todas as classes e não transferem o controle. Você pode verificar dentro dele, talvez o nome do controlador, para ver como foi chamado.

Michael Durrant
fonte
6

Composição para o resgate!

Dado o motivo, em vez de invocar ações entre controladores, deve-se projetar controladores para separar partes compartilhadas e personalizadas do código. Isso ajudará a evitar a duplicação de código e a quebra do padrão MVC.

Embora isso possa ser feito de várias maneiras, usar interesses ( composição ) é uma boa prática.

# 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 ajude.

Oleg Afanasyev
fonte
2

Você pode chamar outra ação dentro de uma ação da seguinte maneira:

redirect_to action: 'action_name'

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

  def action2
  end
end
CodecPM
fonte
-6

Separe essas funções dos controladores e coloque-as no arquivo de modelo. Em seguida, inclua o arquivo de modelo em seu controlador.

Michale.Gaocl
fonte
Sugestão ruim. Vai atrapalhar responsabilidades, aponte para ter MVC. Problemas com chamadas de sessão / cookie no modelo etc.
Ain Tohvri