Nuestra aplicación está funcionando, pero hay dos problemas:
- Los mensajes no se almacenan en la base de datos
- No tenemos suficiente control sobre el formato en que se transmiten los mensajes.
Resolver el primer problema es fácil. Simplemente crearemos un nuevo mensaje una vez que el servidor reciba el mensaje en lugar de emitirlo:
123456#app/channels/room_channel.rb#el resto de los métodosdefspeak(data)Message.create! content: data[$0027message$0027]end
rubí
Lo que pretendemos es transmitir el parcial de _message.html.erb que creamos antes al canal_de_habitación. Normalmente, haríamos esto en el controlador, pero no tenemos uno. Renderizarlo en el modelo, la vista o el canal parece inapropiado. Entonces, ¿dónde podemos ponerlo? Entra en Rails Jobs.
Los trabajos en los rieles son buenos para dos tipos de cosas:
- Tareas grandes que se pueden descomponer en pequeños trozos
- Tareas que deben realizarse en paralelo
Esto significa que se pueden crear y poner en cola múltiples trabajos para que el servidor pueda ejecutar tantos a la vez como sus recursos lo permitan. Cuanto más poder de procesamiento y memoria tenga el servidor, ¡más trabajos puede ejecutar simultáneamente!
Así es como haremos un trabajo de transmisión para los mensajes del chat:
12345#app/models/message.rbclassMessage<ApplicationRecord after_create_commit {MessageBroadcastJob.perform_later self}end
rubí
Primero, crearemos un gancho para después de la creación en el modelo. El gancho after_create_commit significa que un trabajo se ejecutará una vez que el mensaje se haya guardado con éxito en la base de datos. perform_later significa que el trabajo se ejecutará tan pronto como la cola esté vacía.
Generemos MessageBroadCastJob:
1rails g job MessageBroadcast
bash
1234567891011121314#app/jobs/message_broadcast_job.rbclassMessageBroadcastJob<ApplicationJob queue_as :defaultdefperform(message)ActionCable.server. broadcast $0027room_channel$0027, message: render_message(message)endprivatedefrender_message(message)ApplicationController.renderer.render(partial:$0027messages/message$0027, locals:{ message: message })endend
rubí
El método de ejecución del trabajo recibirá el mensaje, hará su magia renderizando el mensaje en el parcial _message.html.erb, y emitirá directamente desde el trabajo.Otra novedad en Rails 5 es que podemos renderizar plantillas fuera del ámbito de un controlador, utilizando el renderizador del ApplicationController . Esta ingeniosa característica se utiliza exactamente para un caso como este en el que no tenemos un MessageController definido pero nos gustaría utilizar sus plantillas.
Sólo queda una cosa por hacer: quitar la alerta y reemplazarla con una función que agregue el parcial a nuestra vista:
1234#app/assets/javascripts/channels/room.coffeereceived:(data)-;$($0027#messages$0027).append data[$0027message$0027]
coffeescript
Haciendo esto, el div de $0027#messages$0027 tendrá el mensaje en la plantilla anexa al DOM. Para aclarar, data[$0027message$0027] contiene lo que se emitió desde el MessageBroadcastJob , es decir, el parcial renderizado _message.html.erb con el mensaje en él.
Ahora puedes empezar a escribir en el cuadro de texto y verás tus mensajes aparecer en el chat.