Ejecutando método de controlador desde un Job

21 views
Skip to first unread message

Johan Donado B.

unread,
Sep 27, 2018, 1:01:04 PM9/27/18
to ror-es

Saludos.

Alguien podría orientarme por favor.

A través de una petición por ajax mi controlador genera un informe.  Como la petición tarda en resolverse opté por colocarlo como una tarea en segundo plano con Active Job y sidekiq.

El tema es que mi Job se ejecuta, pero en él debo ejecutar el método que está en mi controlador para generar el informe, pero cuando ejecuto ese método me comienzan a generar errores tales como que no encuentra params, session, ni tampoco entiende respond_to, render_to_string.  render_to_string lo necesito para generar mi pdf con Wicked_pdf.

No sé que estoy haciendo mal o qué me hace falta.

Muchas gracias de ante mano.

Johan Donado B.

unread,
Sep 27, 2018, 1:04:51 PM9/27/18
to ror-es
En mi controlador, en el método que recibe la petición inicial ejecuto mi Job:

CreaPlanillaNinoninoJob.perform_later params.to_unsafe_hash

Tuve que colocarle to_unsafe_hash porque params me decía que no estaba soportado como parámetro de mi Job.

Luego en mi Job:

class CreaPlanillaNinoninoJob < ApplicationJob
  queue_as :default

  def perform(*args)
    # Do something later

    params = args[0]
    certi_controller = NinoninoController.new.crea_certificados(params)

  end
end


No sé si eso sea correcto.

Francis

unread,
Sep 27, 2018, 2:08:39 PM9/27/18
to ror...@googlegroups.com
Qué quieres conseguir?

La función de Sidekiq es mover tareas largas a segundo plano para no tener un proceso de tu servicio HTTP ocupado durante mucho tiempo. Pero ten en cuenta que si optas por realizar el trabajo en segundo plano tu servidor tiene que responder inmediatamente (antes de que se genere el PDF, en este caso)

Luego, según qué quieras conseguir, hay varias alternativas. Puedes poder el PDF en algún sitio y notificar al usuario cuando esté generado. O puedes enviárselo por email. O puedes pintar un spinner en la página para que al usuario le de la sensación de que su petición se está procesando (que lo está, pero la conexión HTTP ya se cerró) y hacer una llamada AJAX cada 1s para ver si ya se creó el PDF. O lo mismo pero sin hacer llamadas cada cierto tiempo (polling) sino usando algún tipo de websocket.

Pero eso depende de lo que quieras hacer.

La única manera de llamar a un método de un controlador razonable que se me ocurre es hacer la petición HTTP que levante ese controlador, pero es justo lo que queremos evitar. Mueve el código que genera el PDF a otro lugar (app/pdf_generators, por poner un ejemplo, como quieras)

--
--
You received this message because you are subscribed to the Google
Groups "ror-es" group.
To post to this group, send email to ror...@googlegroups.com
To unsubscribe from this group, send email to
ror_es+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/ror_es?hl=en
Rails no escala.

---
You received this message because you are subscribed to the Google Groups "ror-es" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ror_es+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Johan Donado B.

unread,
Sep 27, 2018, 2:12:50 PM9/27/18
to ror-es

Gracias por contestar.

Eso mismo pensé, moverlo a otro lado.  Sin embargo cuando intentaba usar:

pdf =  render_to_string layout: 'pdf.pdf.erb', template: "ninonino/nino_a_nino.html.pdf.erb", pdf: nombre_planilla, orientation: 'Landscape', page_size: 'A4', margin: { top: 35, bottom: 45, left: 5, right: 5}, header:  { html: { template: 'ninonino/nino_a_nino_header.pdf.erb' } }, footer:  { html: { template: 'ninonino/nino_a_nino_footer.pdf.erb' } }

para generar mi PDF me decía que no reconocía render_to_string.

Sergio Cambra

unread,
Sep 27, 2018, 3:40:07 PM9/27/18
to ror...@googlegroups.com

Yo movería el código al job. Yo hice algo similar una vez, tienes que crear un ActionView::Base, extenderlo con los helpers que necesites y definir las variables de instancia necesarias (las que tengas en tu acción) con instance_variable_set, finalmente llamar render en el actionview creado.

 

view_paths = Rails::Application::Configuration.new(Rails.root).paths["app/views"]

av_helper = ActionView::Base.new view_paths

av_helper.extend ControllerHelper

PdfTemplate.prepare_template_for(self, av_helper)

av_helper.instance_variable_set :@record, self

av_helper.render layout: 'pdf.pdf.erb', template: "ninonino/nino_a_nino.html.pdf.erb", pdf: nombre_planilla, orientation: 'Landscape', page_size: 'A4', margin: { top: 35, bottom: 45, left: 5, right: 5}, header:  { html: { template: 'ninonino/nino_a_nino_header.pdf.erb' } }, footer:  { html: { template: 'ninonino/nino_a_nino_footer.pdf.erb' } }

Johan Donado B.

unread,
Sep 27, 2018, 10:07:21 PM9/27/18
to ror-es

Bien.  Teniendo en cuenta todas sus recomendaciones, al final hice lo siguiente:

Saqué el método que me crea los pdf de mi controlador y lo puse en una clase aparte, pero hice que esa clase heredara de ApplicationController.  De esta manera reconoce todos los métodos propios de un controlador y me permite pasar variables de instancia a las vistas para crear los pdf.  Si no lo hacía de este modo, del lado de la vista no me reconocía las variables que le pasaba.

En mi Job, creé una nueva instancia de la nueva clase y llamé al método pasándole los parámetros.  Por si acaso, para evitar confusión con mi controlador original lo encerré en un módulo, pero no creo que fuera necesario.

require 'classes/nino_nino'


class CreaPlanillaNinoninoJob < ApplicationJob
  queue_as
:default

 
def perform(*args)
   
# Do something later

   
params = args[0]


    nino
= NinoNino::NinoNinoController.new
    nino
.crea_certificados params

 
end
end


Nuevamente muchas gracias por su ayuda.


El jueves, 27 de septiembre de 2018, 12:01:04 (UTC-5), Johan Donado B. escribió:
Reply all
Reply to author
Forward
0 new messages