Frameworks

Tutorial Meteor JS: Crear metodos de Publicación

Ultima entrega del tutorial de Mteor JS, aprende Meteor JS con este tutorial creando un clon de Twitter.

Publicado el 18 de Abril de 2016
Compartir

Vamos hoy con el último paso en nuestro tutorial en el que nos encargaremos de las suscripciones y las publicaciones.>

En las librerías del núcleo de Meteor encontramos DDP (Distributed Data Protocol), que no es más que un protocolo encargado de la actualización de datos en vivo, lo cual nos viene que ni pintado para nuestra aplicación, puesto que sigue un patrón de publicación y suscripción. Con esto, si generamos un mensaje, se notificará a nuestros suscriptores de dicho cambio en lugar de ser éstos últimos los que tengan que estar pendientes de si realizamos alguna publicación.>

Publicación/Suscripción de tweets

Comprobemos cómo tendríamos acceso a los tweets desde el lado del cliente si tenemos el paquete autopublish desactivo.

Nano server/js/publications.js
Meteor.publish('tweets', function() {  
  return Tweets.find();
});
Nano client/js/tweetFeed.js
Template.tweetFeed.onCreated(function() {  
  this.subscribe('tweets');
});

Como vemos, el servidor está publicando todos los tweets que almacena y los usuarios se suscriben a éstos dentro de la plantilla definida. El problema llegados a este punto es que los clientes recibirán todos los tweets que publique el servidor y no sólo aquellos de los usuarios a los que esté siguiendo.

Pero podemos modificar levemente el código anterior para filtrar y mostrar los mensajes en función de unos parámetros determinados, como por ejemplo el autor de éstos.

Nano server/js/publications.js
Meteor.publish('tweets', function() {  
  if (this.userId) {
    var username = Meteor.users.findOne({_id: this.userId}).username;
    var currentFollowings = UserUtils.findFollowings(username);

    return Tweets.find({user: { $in: currentFollowings }});
  }
});

Mostrar twetts

Llegamos a un apartado importante, ya que ha causado revuelo en la red social que estamos referenciando en este tutorial. Cómo mostrar los tweets . Hace poco se anunciaba un cambio en los timeline de Twitter en el que los mensajes que mostrarían en función de la popularidad de los autores en lugar aparecer en orden cronológico inverso.

Pues bien, prosigamos con la línea clásica de esta red social de microbloging y situemos los tweets más recientes en lo alto del timeline. Para esto deberemos modificar el fichero tweetBox.js en el servidor.

Nano server/js/tweetBox.js
insertTweet: function(tweet) {  
  if (Meteor.user()) {
    Tweets.insert({
      message: tweet,
      user: Meteor.user().username,
      timestamp: new Date()
    });
  }
}

Con esto podremos cambiar el orden de los tweets directamente desde la solicitud de la suscripción, pero vayamos un paso más allá y determinemos cuántos tweets deberá cargar por defecto. Añadiremos las siguientes modificaciones y archivos:

Nano client/stylesheets/miTwitter.css
/* CSS declarations go here */
.tweetbox-container {
  margin: 30px;
  margin-left: 10px;
}

.tweetbox,.userBox {
  background-color: rgb(240, 247, 254);
}

.tweetbox .btnGroup {
  margin-top: 10px;
  display: flex;
  align-items: center;
}

.tweetbox .charCount {
  margin-right: 10px;
  color: gray;
}

.tweetbox .errCharCount {
  margin-right: 10px;
  color: red;
}

.user-container {
  margin-top: 30px;
  margin-left: 30px;
}

.user-container h4 {
  color: gray;
}

.user-container .table {
  margin-top: 10px;
}

.user-container .table th, .table td {
   border-top: none;
}

.user-container .tableHeader {
  color: gray;
}

.user-container .tableContent {
  color: rgb(117, 187, 251);
  font-size: 150%;
}

.user-container .fullbutton {
  width: 100%;
}

.user-container .input-sm {
  margin-bottom: 5px;
}

.user-container .login {
  margin-bottom: 15px;
}

.followBox {
  background-color: rgb(240, 247, 254);
}

.follow-container {
  margin-top: 30px;
  margin-left: 30px;
}

.follow-container .found-user {
  margin-top: 15px;
  display: flex;
  align-items: center;
}

.follow-container h5 {
  color: gray;
}

.tweetfeed {
  background-color: rgb(240, 247, 254);
}

.tweetfeed-container {
  margin: 30px;
  margin-left: 10px;
}
Nano client/js/tweetFeed.js
Template.tweetFeed.helpers({  
  'tweetMessage': function() {
    return Tweets.find({}, { 
        sort: {timestamp: -1}, 
        limit: 10
    });
  }
});
Nano client/templates/tweetFeed.html
<template name="tweetFeed">  
  <div class="tweetfeed-container">
    <div class="panel panel-default tweetfeed">
      <div class="panel-body">
        <!-- Texto para el contenido del tweet -->
        {{#each tweetMessage}}
          <div class="panel panel-info">
            <div class="panel-heading">
              <h3 class="panel-title">@{{this.user}} 
                <span class="glyphicon glyphicon-triangle-right" aria-hidden="true"></span>
                 {{this.timestamp}}
               </h3>
            </div>
            <div class="panel-body">
              {{this.message}}
            </div>
          </div>
        {{/each}}
      </div>
    </div>
  </div>
</template> 

Ahora ya seríamos capaces de ver actualizaciones de mensajes del timeline en tiempo real.

Publicaciones Reactivas

De acuerdo, ya tenemos creado el sistema de usuarios que queríamos, pero si nos fijamos un poco, al seguir a un usuario nuevo sus publicaciones no nos aparecerán inmediatamente en nuestro timeline hasta que no volvamos a iniciar sesión. Esto es debido a que el método definido en el servidor sólo va a servir a los clientes aquello cargado en el cursor de la base de datos en el momento en que accedemos a ella en el inicio de sesión, y todos los cambios en las dependencias del cursor no se verán reflejados hasta volver a entrar en el sistema.

Esto tiene solución gracias de nuevo a la cantidad de recursos que Meteor pone a nuestra disposición, así que dentro de nuestra carpeta del proyecto escribiremos:

meteor add reywood:publish-composite 

Y completamos con estos bloques de código los siguientes archivos:

Nano server/js/publications.js
Meteor.publishComposite('tweets', function(username) {  
  return {
    find: function() {
      // Comprobar los usuarios a los que se está siguiendo
      return Relationships.find({ follower: username });
    },
    children: [{
      find: function(relationship) {
        // Encontrar mensajes de los usuarios que se siguen
        return Tweets.find({user: relationship.following});
      }
    }]
  }
});

Meteor.publish('ownTweets', function(username) {  
  return Tweets.find({user: username});
});

Como vemos, acabamos de definir el método Meteor.publishComposite() al que añadimos una función find: function() que se encargará de vigilar los cambios en la base de datos “relationships”, que serán pasados a cada función find: function() de cada hijo en este método. Éstos a su vez generarán solicitudes para obtener todos los tweets de cada usuario que se les haya pasado para así obtener una lista actualizada a cada momento.

Pero además también queremos que se muestren los mensajes del usuario que se encuentra registrado, y es por esto por lo que definimos el método Meteor.publish(‘ownTweets’, function(username)) , con el que además de los mensajes de los usuarios a quienes seguimos, podremos ver los nuestros propios.

Nano client/js/tweetFeed.js
Template.tweetFeed.onCreated(function() {  
  if (Meteor.user()) {
    this.subscribe('tweets', Meteor.user().username);
    this.subscribe('ownTweets', Meteor.user().username);
  }
});

Añadiendo esta línea a nuestro archivo tweetFeed.js en el lado del cliente, nos acabamos de suscribir a nuestros propios mensajes, para que lo que hemos definido en el archivo anterior tenga total funcionalidad.

Uso del método Publicación/Suscripción en las recomendaciones de usuario.

Ahora que sabemos cómo realizar publicaciones y suscripciones podemos mejorar nuestro sistema de recomendaciones de usuarios a seguir. Crearemos una lista de usuarios sugeridos para seguir, en la que al pulsar sobre ellos los añadiremos a nuestra lista de “siguiendo” y éste desaparecerá de dicha lista dando paso a otra recomendación.

Esto lo podemos hacer en el lado del cliente en lugar de en el servidor, dado que no hay involucrados datos que haya que ocultar a los usuarios. Todo lo que necesitamos es una lista de nombres de usuarios, y aquellos que ya sigue el usuario registrado.

Nano server/js/publications.js
// Lista de todos los usuarios
Meteor.publish('users', function(username) {  
  return Meteor.users.find({}, {
    fields: { 'username': 1 },
    limit: 100
  });
});

// Lista de usuarios seguidos por el usuario
Meteor.publish('followings', function(username) {  
  return Relationships.find({ follower: username });
});

Con esto el usuario ya dispone de las dos bases de datos que necesita para recibir las sugerencias sin duplicados en ellas.

Nano client/js/followUsers.js
Template.followUsers.helpers({  
  'recommendedUsers': function() {
    if (Meteor.user()) {
      var currentFollowings = UserUtils.findFollowings(Meteor.user().username);

      var recUsers = Meteor.users.find({
        username: {
          $nin: currentFollowings
        }
      }, {
        fields: { 'username': 1 },
        limit: 5
      }).fetch();

      return recUsers;
    }
  }
});

Template.followUsers.onCreated(function() {  
  if (Meteor.user()) {
    this.subscribe('users', Meteor.user().username)
    this.subscribe('followings', Meteor.user().username);
  }
});

Y una vez más queda demostrada la versatilidad de Meteor, gracias a la cual no necesitaremos modificar una sola línea de código en los ficheros del lado del servidor para que estos cambios funcionen correctamente en el cliente.

Uso de Publicación/Suscripción en el perfil del usuario

Vamos con los últimos cambios a realizar relacionados con las publicaciones y suscripciones. A estas alturas podemos ver cómo nuestro perfil no muestra ninguna información actualizada más allá del nombre de usuario. Vamos a solucionar esto, ya que en la red social en la que nos fijamos sí que podemos ver el número de tweets que hemos publicado, los seguidores de nuestro perfil, etc… e implementar esto no será en absoluto complicado.

Necesitaremos publicar otro conjunto de información con el que obtener el contador de seguidores:

Nano server/js/publications.js
Meteor.publish('followers', function(username) {  
  return Relationships.find({ following: username });
});

A continuación en la plantilla cliente usaremos el método count() de MongoDB para obtener el número de seguidores, de usuarios a los que sigue este usuario y los tweets que ha publicado:

Nano client/js/userManagement.js
Template.userManagement.helpers({  
  'tweets': function() {
    if (Meteor.user()) {
      return Tweets.find({ user: Meteor.user().username }).count();
    }
  },

  'following': function() {
    if (Meteor.user()) {
      return Relationships.find({ follower: Meteor.user().username }).count();
    }
  },

  'followers': function() {
    if (Meteor.user()) {
      return Relationships.find({ following: Meteor.user().username }).count();
    }
  }
});

Template.followUsers.onCreated( function() {  
  if (Meteor.user()) {
    this.subscribe('followings', Meteor.user().username);
    this.subscribe('followers', Meteor.user().username);
    this.subscribe('tweets', Meteor.user().username);
  }
});
Nano client/templates/userManagement.html
{{# if currentUser}}
<!—Mensaje para el usuario registrado -->  
<p>Hola <strong>@{{currentUser.username}}</strong>, bienvenido a tuTwitter en miTwitter</p>  
<button type="button" class="btn btn-info fullbutton" id="logout">Salir</button>

<table class="table">  
  <tr>
    <td class="tableHeader">Tweets</td>
    <td class="tableHeader">Siguiendo</td>
    <td class="tableHeader">Seguidores</td>
  </tr>
  <tr>
    <td class="tableContent">{{tweets}}</td>
    <td class="tableContent">{{following}}</td>
    <td class="tableContent">{{followers}}</td>
  </tr>
</table>

{{else}}

Y con esto ya podremos ver cómo nuestro timeline y estadísticas se actualizan en tiempo real gracias a la efectividad de Meteor. Aquí un ejemplo de cómo quedaría la interfaz, creando tres usuarios (@Openwebinars, @Toushiro y @Zaraki) dos de ellos se están siguiendo entre sí, por lo que verían sus mensajes mientras que @Zaraki no podría. No obstante vemos cómo en las recomendaciones a todos los usuarios le aparecerán aquellos que no estén siguiendo, por lo que sólo faltaría comenzar a publicar mensajes ;)

Imagen 0 en Tutorial Meteor JS: Crear metodos de Publicación

Os dejo una captura de cómo debería quedar nuestro árbol de directorios así como un enlace a la estructura de la aplicación al finalizar este tutorial.

Imagen 1 en Tutorial Meteor JS: Crear metodos de Publicación

Enlace a la estructura de la aplicación .

Además cabe hacer mención a que no hace mucho tiempo, Meteor recibió un importante respaldo tanto económico como empresarial a fin de ampliar aún más sus posibilidades y evolucionar para ofrecer componentes actuales y de gran estabilidad.

No obstante, mientras sigue su curso, los usuarios y comunidades de desarrollo continúan aportando paquetes a su repositorio, los cuales podemos implementar en nuestros proyectos libremente, encontrando en la mayoría de las ocasiones módulos muy completos que nos ahorrarán el tener que desarrollarlos y por ende, horas de trabajo en la creación de nuestras web-apps.


Compartir este post

También te puede interesar...

Tecnología

Tutorial Meteor JS: Interfaz y registro en BD

29 Marzo 2016 Esaú Abril Nuñez
Tecnología

Tutorial Meteor JS: Estructura y Seguridad

05 Abril 2016 Esaú Abril Nuñez
Artículos
Ver todos