Showing users

In this section, we’ll take the first steps toward the final profile by making a page to display a user’s name and profile photo. Our eventual goal for the user profile pages is to show the user’s profile image, basic user data, and a list of microposts. We’ll complete this task, and with it the sample application, in “Following users” Chapter.

A Users resource

In order to make a user profile page, we need to have a user in the database. Happily, this problem has already been solved: in previous post, we created a User record by hand using the console

> require ( 'trainjs' ). initServer () > User . count (). then ( function ( data ){ console . log ( data ) }) 1 > User . findOne (). then ( function ( data ){ console . log ( data ) }) { dataValues : { id : 1 , name : 'Dang Thanh' , email : [email protected]' , password_digest : '$2a$10$7gVwYayQoKFSEkJfobhAne4EjC52Djt7x1cl9cponFtAn.zVtfP0e' , createdAt : Fri Jan 29 2016 12 : 30 : 00 GMT + 0700 ( ICT ), updatedAt : Fri Jan 29 2016 12 : 30 : 00 GMT + 0700 ( ICT ) }, ...

When following REST principles, resources are typically referenced using the resource name and a unique identifier. What this means in the context of users—which we’re now thinking of as a Users resource—is that we should view the user with id 1 by issuing a GET request to the URL /users/1 .

We can get the routing for /users/1 to work by running a single command

~/sample_app $ trainjs generate service User show create app/controllers/users_controller.js create public/services create public/services/user.js

The result appears in config/routes.js

module . exports = [ { resources : 'users' } ];

We’ll use the standard trainjs location for showing a user, which is public/partials/users/show.html

{{ user.name }}, {{ user.email }}

public/app.js

'use strict' ; var sampleApp = angular . module ( 'sampleApp' , [ 'ui.router' , 'userService' , 'usersController' , 'staticPagesController' , 'bodyDirective' , 'headDirective' ]); sampleApp . config ([ '$stateProvider' , '$urlRouterProvider' , function ( $stateProvider , $urlRouterProvider ) { $urlRouterProvider . otherwise ( '/home' ); $stateProvider ... . state ( 'user_detail' , { url : '/users/:id' , templateUrl : 'partials/users/show.html' , resolve : { user : [ '$q' , '$stateParams' , 'User' , function ( $q , $stateParams , User ){ var deferred = $q . defer (); User . get ({ id : $stateParams . id }, function ( user ) { deferred . resolve ( user ); }, function ( error ) { deferred . reject (); }); return deferred . promise ; }] }, controller : 'UsersDetailCtrl' }) }]); ...

In order to get the user show view to work, we need to define an user variable in the corresponding show action in the Users controller.

app/controllers/users_controller.js

function UsersController () { this . show = function ( req , res , next ) { var user = ModelSync ( User . findById ( req . params . id ) ); res . end ( JSON . stringify ( user )); }; }; module . exports = UsersController ;

public/controllers/users_controller.js

'use strict' ; var usersController = angular . module ( 'usersController' , []); usersController . controller ( 'UsersNewCtrl' , [ '$scope' , function ( $scope ) { }] ); usersController . controller ( 'UsersDetailCtrl' , [ '$scope' , '$rootScope' , 'user' , function ( $scope , $rootScope , user ) { $rootScope . provide_title = user . name ; $scope . user = user ; }] );

A Gravatar image and a sidebar

Gravatar is a free service that allows users to upload images and associate them with email addresses they control. Our plan is to define a gravatar_for directive for a given user.

public/partials/users/show.html

<h1> <img gravatar_for= "{{ user.email }}" alt= "{{ user.name }}" /> {{ user.name }} </h1>

public/index.html

... <script src= "directives/body.js" ></script> <script src= "directives/head.js" ></script> <script src= "directives/gravatar_for.js" ></script> ...

public/app.js

'use strict' ; var sampleApp = angular . module ( 'sampleApp' , [ 'ui.router' , 'userService' , 'usersController' , 'staticPagesController' , 'bodyDirective' , 'headDirective' , 'gravatarForDirective' ]); ...

public/directives/gravatar_for.js

var gravatarForDirective = angular . module ( 'gravatarForDirective' , [ 'angular-md5' ]); gravatarForDirective . directive ( 'gravatarFor' ,[ 'md5' , function ( md5 ) { return { restrict : 'A' , link : function ( scope , elem , attrs ) { var gravatar_id = md5 . createHash ( attrs . gravatarFor . toLowerCase ()); var gravatar_url = "https://secure.gravatar.com/avatar/" + gravatar_id ; elem . attr ( 'src' , gravatar_url ); } }; }]);

As noted in the Gravatar documentation, Gravatar URLs are based on an MD5 hash of the user’s email address. In the demo, the MD5 hashing algorithm is implemented using the angular-md5 library

~/sample_app $ npm install angular-md5 --save

public/index.html

... <script src= "libs/angular.min.js" ></script> <script src= "libs/angular-ui-router.min.js" ></script> <script src= "libs/angular-resource.min.js" ></script> <script src= "../node_modules/angular-md5/angular-md5.min.js" ></script> ...

The profile page appears above, which shows the default Gravatar image, which appears because [email protected] isn’t a real email address.

To get our application to display a custom Gravatar, we’ll use update to change the user’s email to something I control

> require ( 'trainjs' ). initServer () > var user ; > User . findOne (). then ( function ( data ){ user = data }) > user . update ({ name : "Example User" , email : [email protected]" , password : "foobar" , password_confirmation : "foobar" })

Here we’ve assigned the user the email address [email protected], which I’ve associated with the Rails Tutorial logo

We include row and col-md-4 classes in the user show page public/partials/users/show.html

<div class= "row" > <aside class= "col-md-4" > <section class= "user_info" > <h1> <img gravatar_for= "{{ user.email }}" alt= "{{ user.name }}" /> {{ user.name }} </h1> </section> </aside> </div>

public/assets/stylesheets/custom.css