Lo primero que vamos a hacer es crear el modelo y el controlador , para ello ejecutaremos la siguiente sentencia en la consola:

~/videoclub $ sails generate api user


Mediante el atributo api generamos el modelo y el controlador; Si quisiéramos crear únicamente el modelo utilizaríamos el atributo model ; Y si quisiéramos crear únicamente el controlador utilizaríamos el atributo controller .

Ahora, en el modelo escribiremos los siguiente:

      /**
        * User.js
        *
        * @description :: TODO: You might write a short summary of how this model works and what it represents here.
        * @docs        :: http://sailsjs.org/#!documentation/models
        */

        module.exports = {

          attributes: {

            name: {
              type: 'string',
              required: true
            },
            lastname: {
              type: 'string',
              required: true
            },
            email: {
              type: 'string',
              required: true,
              unique: true
            },
            encryptedPassword: {
              type: 'string'
            },

            // Este método es para evitar pasar toda la información del modelo
            // Evitamos pasar los siguientes parámetros: password, confirmation, encryptedpassword y _csrf. 
            toJSON: function() { 
              var obj = this.toObject();
              delete obj.password;
              delete obj.confirmation;
              delete obj.encryptedPassword;
              delete obj._csrf;
              return obj;
            }
          }
        };

Los atributos que permite sails son los siguientes: string , text , integer , float , date , datetime , boolean , binary , array , json , email .

Además, podemos especificar si el atributo es obligatorio, único, su valor por defecto, etc. Todo esto nos permite crear un modelo de manera muy simple y nos abstrae a la hora de crearlo en la base de datos gracias a waterline .

Dentro del modelo podemos crear los métodos que deseemos y unos callbacks que se ejecutarán antes de ciertas acciones.

Callbacks on create

  • beforeValidate: fn(values, cb)
  • afterValidate: fn(values, cb)
  • beforeCreate: fn(values, cb)
  • afterCreate: fn(newlyInsertedRecord, cb)

Callbacks on update

  • beforeValidate: fn(valuesToUpdate, cb)
  • afterValidate: fn(valuesToUpdate, cb)
  • beforeUpdate: fn(valuesToUpdate, cb)
  • afterUpdate: fn(updatedRecord, cb)

Callbacks on destroy

  • beforeDestroy: fn(criteria, cb)
  • afterDestroy: fn(destroyedRecords, cb)

Más adelante veremos como utilizarlos.

Después iremos a views y crearemos la carpeta user y dentro de dicha carpeta los ficheros index.ejs :

      <div class="container">
      <h3>Usuarios
      <table class='table'>
          <tr>
              <th>ID
              <th>Nombre
              <th>Apellidos
              <th>Email
              <th>
              <th>
              <th>
          </tr>
          <% _.each(users, function(user) { %>
          <tr data-id="<%= user.id %>" data-model="user">
              <td><%= user.id %>
              <td><%= user.name %>
              <td><%= user.lastname %>
              <td><%= user.email %>
              <td><a href="/user/show/<%= user.id %>" class="btn btn-sm btn-primary">Show</a>
              <td><a href="/user/edit/<%= user.id %>" class="btn btn-sm btn-warning">Edit</a>
            <td><form action="/user/destroy/<%= user.id %>" method="POST"> 
                      <input type="hidden" name="_method" value="delete"/>
                      <input type="submit" class="btn btn-sm btn-danger" value="Delete"/>
                      <input type="hidden" name="_csrf" value="<%= _csrf %>" />
                  </form>
              </td>
          </tr>
          <% }) %>
      </table>
      <a href="/user/new">Crear Nuevo Usuario</a>
      </div>


Como podemos ver lo que hacemos es crear una tabla donde mostraremos la información de cada usuario creado.


Respecto al código podemos ver la siguiente línea: <% _.each(user, function(user) { %>


Lo que hace es recorrer cada uno de los usuarios (users) y llama a la funcion function(user) donde le pasa el user.id buscando dentro del modelo mediante data-id pasandole el nombre del modelo: data-model="user" .

        <% _.each(users, function(user) { %>
        <tr data-id="<%= user.id %>" data-model="user">
            <td><%= user.id %>
            <td><%= user.name %>
            <td><%= user.lastname %>
            <td><%= user.email %>
            <td><a href="/user/show/<%= user.id %>" class="btn btn-sm btn-primary">Show</a>
            <td><a href="/user/edit/<%= user.id %>" class="btn btn-sm btn-warning">Edit</a>
            <td><form action="/user/destroy/<%= user.id %>" method="POST"> 
                  <input type="hidden" name="_method" value="delete"/>
                  <input type="submit" class="btn btn-sm btn-danger" value="Delete"/>
                  <input type="hidden" name="_csrf" value="<%= _csrf %>" />
                </form>
              </td>
          </tr>
        <% }) %>


Y ahora el fichero new.ejs :

          <form action="/user/create" method="POST" class="form-signin">
            <h2 class="form-signin-heading"> Crear Usuario 
            <div class="control-group"> 
            <input type="text" class="form-control" placeholder="Nombre" name="name">
            </div>
            <div class="control-group">
                  <input type="text" class="form-control" placeholder="Apellidos" name="lastname">
                  </div>
                  <div class="control-group">
                  <input type="text" class="form-control" placeholder="Email" name="email">
                  </div>
                  <div class="control-group">
                  <input type="password" class="form-control" placeholder="Contraseña" name="password">
                  </div>
                  <div class="control-group">
                  <input type="password" class="form-control" placeholder="Repita Contraseña" name="confirmation">
                  </div>
            <br/>
                  <input type="submit" class="btn btn-lg btn-primary btn-block" value="Create User"/>
                  <input type="hidden" name="_csrf" value="<%=_csrf %>"/>
          </form>


Ahora vamos al controlador y cremos los métodos para dichas vistas. Los nombres serán los que están en el action .

          /**
           * UserController
           *
           * @description :: Server-side logic for managing users
           * @help        :: See http://links.sailsjs.org/docs/controllers
           */

          module.exports = {
            'new': function (req, res) {
              res.view();
            },
            index: function (req, res) {
              User.find(function foundUser (err, users) {
                if(err) return res.redirect('/user/new');
                res.view({
                  users: users
                });
              });
            },
            create: function(req, res) {
                User.create(req.params.all(), function userCreated(err, user) {
                  if (err) return res.redirect('/user/new');
                  res.redirect('/user/show/' + user.id); 
                });
              }
          };


Finalmente, accedemos al archivo routes.js y añadimos una nueva ruta para que cuando accedamos a cualquier vista de user no redireccione a 403, sino que permita renderizar las vistas. Para ello añadiremos el siguiente código debajo de la ruta raíz con una coma (,).

module.exports.policies = {

            // '*': true,

            'user': {
              'new': true,
              index: 'sessionAuth',
              '*': true
            }
          };


Que significa esto, pues vamos a explicar:

La parte comentada, // '*': true, significa que cualquier vista que se muestre tendrá todos los accesos y permisos abiertos.

Ahora hemos insertado 'user' que es el nombre del modelo y dentro damos los permisos para cada método del controlador. Como podemos ver para poder acceder a 'index' deberemos estar autenticados, si no lo estamos nos redireccionará la vista 'new' (dentro del metodo create: if (err) return res.redirect('/user/new'); ). sessionAuth hace referencia al fichero sessionAuth.js que está en api/policies.

Y para el resto de operaciones ( '*' ) tenemos todos los accesos, es decir no tenemos ninguna reestricción, como la necesidad de estar autenticados.