Web Programming examples

Google Maps,AngularJS

Archives

Ruby on Rails Tutorial add follower stats to the profile page

1)Rails controller

$ vi app/controllers/users_controller.rb

  def show
    user = User.find(params[:id])
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    microposts = user.microposts
    @user_info = {
      user: user,
      gravatar_url: "https://secure.gravatar.com/avatar/#{gravatar_id}",
      microposts: microposts,
      followed_users: user.followed_users,
      followers:  user.followers
    }
    render json: @user_info
  end

2)AngularJS template view

$ vi app/assets/templates/users/show.html.erb

<div class="col-xs-6 col-sm-4">
  <h3>
    <img alt="{{user_info.user.name}}" src="{{user_info.gravatar_url}}" />
      {{user_info.user.name}}
  </h3>
  <div class="stats">
    <a href="#">
      <strong id="following" class="stat">
        {{user_info.followed_users.length}}
      </strong>
      following
    </a>
    <a href="#">
      <strong id="followers" class="stat">
        {{user_info.followers.length}}
      </strong>
      followers
    </a>
  </div>
</div>

Ruby on Rails Tutorial showing microposts with AngularJS

1)Rails controller

$ vi app/controllers/users_controller.rb

  def show
    user = User.find(params[:id])
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    microposts = user.microposts
    @user_info = {
      user: user,
      gravatar_url: "https://secure.gravatar.com/avatar/#{gravatar_id}",
      microposts: microposts
    }
    render json: @user_info
  end

2)AngularJS template view

$ vi app/assets/templates/users/show.html.erb

<div ng-controller="UsersShowCtrl">
  <div class="row">
.......
    <div class="col-xs-6 col-sm-8">
      <h3>Microposts({{user_info.microposts.length}})</h3>
      <ol class="microposts">
        <li ng-repeat="mp in user_info.microposts">
          <div>{{mp.content}}</div>
          <small class="text-muted">Posted {{mp.created_at | date:'medium'}}</small>
        </li>
      </ol>
    </div>
  </div>
</div>

3)css

$ vi app/assets/stylesheets/custom.css.scss

/* microposts */

.microposts {
  list-style: none;
  margin: 10px 0 0 0;

  li {
    padding: 10px 0;
    border-top: 1px solid #e8e8e8;
  }
}

Ruby on Rails Tutorial updating users with AngularJS

(1)Rails controller

$ vi app/controllers/users_controller.rb

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      render json: @user, status: :created, location: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

(2)AngularJS route

$ vi app/assets/javascripts/mymodule.js.erb

myModule = angular.module('myModule', ['ui.bootstrap','ngRoute','ngResource']);

myModule.config(function($routeProvider, $locationProvider) {
  $locationProvider.html5Mode(true);
  $routeProvider
........
    .when("/users/:id/edit", {
     templateUrl: "<%= asset_path('users/new.html.erb') %> "
     })

(3)AngularJS controller

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersNewCtrl", function($scope, userResource, $location, flashService, $routeParams) {
  if ($routeParams.id) {
    var msg = "Profile updated";
    $scope.title = "Update your profile";
    $scope.btn_name = "Save changes";
    userResource.show({ id: $routeParams.id }, function(user_info) {
      $scope.user = user_info.user;
      $scope.gravatar_url = user_info.gravatar_url;
    })
  } else {
    var msg = "Welcome to the Sample App!";
    $scope.title = "Sing up";
    $scope.btn_name = "Create my account";
    $scope.user = new userResource();
  }
  $scope.submit = function() {
.......
    if ($routeParams.id) {
      userResource.update($scope.user, success, failure);
    } else {
      userResource.create($scope.user, success, failure);
    }
  };

ref.
Rails controller 

  def show
    user = User.find(params[:id])
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    @user_info = {
      user: user,
      gravatar_url: "https://secure.gravatar.com/avatar/#{gravatar_id}"
    }
    render json: @user_info
  end

(4)AngularJS template view

$ vi app/assets/templates/users/new.html.erb

<h1 class="text-center">{{title}}</h1>
.....
<button ng-click="submit()" class="btn btn-primary"
         ng-disabled="userNewForm.$invalid" >
  {{btn_name}}
</button>
......
<span ng-show="user.id">
  <img alt="{{user.name}}" src="{{gravatar_url}}" />
  <a href="http://gravatar.com/emails">change</a>
</span>

(5)add link to navigation menu

$ vi app/views/layouts/_header.html.erb

<li><%= link_to "Settings", "/users/{{chkSignin().user.id}}/edit" %></li>

Ruby on Rails Tutorial log out with AngularJS

1)Rails route

$ rake routes

match '/app/sessions', to: 'sessions#destroy', via: 'delete'

2)AngularJS "sessionResource" service

$ vi app/assets/javascripts/mymodule.js.erb

myModule.factory("sessionResource", function($resource) {
  return $resource("/app/sessions", {},
    {
      'create':  { method: 'POST' },
      'destroy': { method: 'DELETE' },
      'current_user': { method: 'GET', isArray: false }
    }
  );
});

3)Rails controller

$ vi app/controllers/sessions_controller.rb

  def destroy
    cookies.delete(:remember_token)
    head :no_content
  end

4)add link to navigation menu

$ vi app/views/layouts/_header.html.erb

<li><a href="" ng-click="signout()">Sign out</a></li>

5)AngularJS controller

$ vi app/assets/javascripts/mymodule.js.erb

function CollapseDemoCtrl($scope, flashService, sessionResource, $location) {
  $scope.signout = function() {
    sessionResource.destroy({}, function(response) {
      flashService.setUser(null);
      $location.path("/");
    });
  };
}

Ruby on Rails Tutorial user log in, session with AngularJS

(1)remembering users'sessions

1)add a column to User model

1.generate a migration

$ rails generate migration add_remember_token_to_users

2.add "remember_token" column

$ vi db/migrate/…_add_remember_token_to_users.rb

class AddRememberTokenToUsers < ActiveRecord::Migration
  def change
    add_column :users, :remember_token, :string
    add_index  :users, :remember_token
  end
end

3.migration

$ bundle exec rake db:migrate

2)Adding a method for generating tokens

$ vi app/models/user.rb

class User < ActiveRecord::Base
.......
  before_create :create_remember_token
.......
  def User.new_remember_token
    SecureRandom.urlsafe_base64
  end

  def User.encrypt(token)
    Digest::SHA1.hexdigest(token.to_s)
  end

  private
    def create_remember_token
      self.remember_token = User.encrypt(User.new_remember_token)
    end
end

3)Rails "sessions" controller

$ vi app/controllers/sessions_controller.rb

  def create
    user = User.find_by(email: session_params[:email].downcase)
    if user && user.authenticate(session_params[:password])
      remember_token = User.new_remember_token
      cookies.permanent[:remember_token] = remember_token
      user.update_attribute(:remember_token, User.encrypt(remember_token))
      @user_info = {
        user: user
      }
      render json: @user_info, status: :accepted, location: user
    else
      msg = {"password" => ["Invalid email/password combination"]}
      render json: msg, status: :unprocessable_entity
    end
  end

private
  def session_params
    params.permit(:email,:password)
  end

4)AngularJS controller

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("SessionsNewCtrl", function($scope, sessionResource, $location) {
  $scope.submit = function() {
    function success(response) {
      $location.path("/users/" + response.user.id);
    }
    function failure(response) {
........
    }
    sessionResource.create($scope.session, success, failure);
  };
});

Ruby on Rails Tutorial AngularJS form, validating form server-side

(1)Rails validation

$ vi app/models/user.rb

class User < ActiveRecord::Base
  validates :password, length: { minimum: 6 }
  validates :name,  presence: true, length: { maximum: 20 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
end

(2)AngularJS controller

1)underscore.js include

$ vi app/assets/javascripts/application.js

//= require underscore-min

2)AngularJS controller "UsersNewCtrl"

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersNewCtrl", function($scope, userResource, $location, flashService) {
.....
  $scope.submit = function() {
.......
    function failure(response) {
      _.each(response.data, function(errors, key) {
        _.each(errors, function(e) {
          $scope.userNewForm[key].$dirty = true;
          $scope.userNewForm[key].$setValidity(e, false);
        });
      });
    }
    userResource.create($scope.user, success, failure);
  };
  $scope.errorMessage = function(name) {
    var s = $scope.userNewForm[name].$error;
    result = [];
    _.each(s, function(key, value) {
      result.push(name + " " + value);
    });
    return result.join(", ");
  };
});

(3)AngularJS template view

$ vi app/assets/templates/users/new.html.erb

<div ng-controller="UsersNewCtrl" class="row">
<style>
  form.ng-invalid.ng-dirty { background-color: lightpink; }
  form.ng-valid.ng-dirty { background-color: lightgreen; }
  form { padding: 10px;}
</style>
  <div class="col-md-6 col-md-offset-3">
    <h1 class="text-center">Sign up</h1>
    <form name="userNewForm" novalidate>
      <div class="well">
        <div class="form-group" ng-class="{'has-error': userNewForm.name.$invalid && userNewForm.name.$dirty}">
          <label>Name</label>
          <input name="name" class="form-control"
            ng-model="user.name"
            required
            ng-maxlength="20" />
          <span class="text-danger" ng-show="userNewForm.name.$dirty && userNewForm.name.$error.required">
            Name can't be blank
          </span>
          <span class="text-danger" ng-show="userNewForm.name.$dirty && userNewForm.name.$error.maxlength">
            Name is too long (maximum is 20 characters)
          </span>
          <span class="text-danger" ng-show="userNewForm.name.$dirty && userNewForm.name.$invalid">
            {{errorMessage('name')}}
          </span>
        </div>
        <div class="form-group" ng-class="{'has-error': userNewForm.email.$invalid && userNewForm.email.$dirty}">
          <label>Email</label>
          <input type="email" name="email" class="form-control"
            ng-model="user.email"
            required />
          <span class="text-danger" ng-show="userNewForm.email.$dirty && userNewForm.email.$error.required">
            Email can't be blank
          </span>
          <span class="text-danger" ng-show="userNewForm.email.$dirty && userNewForm.email.$error.email">
            Email is invalid
          </span>
          <span class="text-danger" ng-show="userNewForm.email.$dirty && userNewForm.email.$invalid">
            {{errorMessage('email')}}
          </span>
        </div>
        <div class="form-group" ng-class="{'has-error': userNewForm.password.$invalid && userNewForm.password.$dirty}">
          <label>Password</label>
          <input type="password" name="password" class="form-control"
            ng-model="user.password"
            required
            ng-minlength="6" />
          <span class="text-danger" ng-show="userNewForm.password.$dirty && userNewForm.password.$error.required">
            Password can't be blank
          </span>
          <span class="text-danger" ng-show="userNewForm.password.$dirty && userNewForm.password.$error.maxlength">
            Password is too short (minimum is 6 characters)
          </span>
          <span class="text-danger" ng-show="userNewForm.password.$dirty && userNewForm.password.$invalid">
            {{errorMessage('password')}}
          </span>
        </div>
        <div class="form-group" ng-class="{'has-error': userNewForm.password_confirmation.$invalid && userNewForm.password_confirmation.$dirty}">
          <label>Password_confirmation</label>
            <input type="password" name="password_confirmation"
              class="form-control"
              ng-model="user.password_confirmation"
              required
              ng-minlength="6" />
          <span class="text-danger" ng-show="userNewForm.password_confirmation.$dirty && userNewForm.password_confirmation.$error.required">
            Password_confirmation can't be blank
          </span>
          <span class="text-danger" ng-show="userNewForm.password_confirmation.$dirty && userNewForm.password_confirmation.$error.maxlength">
            Password_confirmation is too short (minimum is 6 characters)
          </span>
          <span class="text-danger" ng-show="userNewForm.password_confirmation.$dirty && userNewForm.password_confirmation.$invalid">
            {{errorMessage('password_confirmation')}}
          </span>
        </div>
        <button ng-click="submit()" class="btn btn-primary"
                 ng-disabled="userNewForm.$invalid" >
          Create my account
        </button>
        <button ng-click="resetError(userNewForm)" class="btn btn-primary">
          Reset Error
        </button>
      </div>
    </form>
  </div>
</div>

Ruby on Rails Tutorial flash message to user signup with AngularJS

1)flash message with AngularJS

$ vi app/assets/javascripts/mymodule.js.erb

myModule.factory("flashService", function ($rootScope) {
  var queue = [];
  var currentMessage = "";

  $rootScope.$on("$routeChangeSuccess", function() {
    currentMessage = queue.shift() || "";
  });

  return {
    push: function (msg) {
      queue.push(msg);
    },
    get: function () {
      return currentMessage;
    }
  };
});

*routeChangeSuccess
ref.https://docs.angularjs.org/api/ngRoute/service/$route

2)AngularJS controller "UsersNewCtrl"

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersNewCtrl", function($scope, userResource, $location, flashService) {
  var msg = "Welcome to the Sample App!";
  $scope.user = new userResource();
  $scope.submit = function() {
    function success(response) {
      flashService.push(msg);
      $location.path("/users/" + response.id);
    }
    function failure(response) {
      console.log("failure", response)
    }
    userResource.create($scope.user, success, failure);
  };
});

3)AngularJS show view

1.show view

$ vi app/assets/templates/users/show.html.erb

<div ng-controller="UsersShowCtrl">
  <div class="row">
    <div class="bg-success" ng-show="getMessage()">
      <p>{{getMessage()}}</p>
    </div>
........

2.AngularJS controller "UsersShowCtrl"

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersShowCtrl", function($scope, $routeParams, userResource, flashService) {
  $scope.user = userResource.show({ id: $routeParams.id });
  $scope.getMessage = function() {
    return flashService.get();
  };
});

Ruby on Rails Tutorial user signup with AngularJS

(1)Adding a secure password

1)configuration

1.bcrypt-ruby install

$ vi Gemfile

gem 'bcrypt'

$ bundle install

2.add "password_digest" columns to the users table

$ rails generate migration add_password_digest_to_users password_digest:string
      invoke  active_record
      create    db/migrate/20150713044621_add_password_digest_to_users.rb

$ more db/migrate/20150713044621_add_password_digest_to_users.rb

class AddPasswordDigestToUsers < ActiveRecord::Migration
  def change
    add_column :users, :password_digest, :string
  end
end

3.migration

$ bundle exec rake db:migrate

4.User model "has_secure_password" method

$ vi app/models/user.rb

class User < ActiveRecord::Base
  has_secure_password
end

2)create test users

$ vi rails c

2.0.0p247 :004 > test = User.create(name: "testuser4", email: "test4@example.com", password: "test4pass", password_confirmation: "test4pass")
 => #<User id: 4, name: "testuser4", email: "test4@example.com", created_at: "2015-07-13 04:51:06", updated_at: "2015-07-13 04:51:06", password_digest: "$2a$…">

(2)AngularJS Signup form

1)AngularJS route

$ vi app/assets/javascripts/mymodule.js.erb

myModule = angular.module('myModule', ['ui.bootstrap','ngRoute','ngResource']);

myModule.config(function($routeProvider, $locationProvider) {
  $locationProvider.html5Mode(true);
  $routeProvider
.......
    .when("/users/new", {
     templateUrl: "<%= asset_path('users/new.html.erb') %>"
     })

2)AngularJS template new view

$ vi app/assets/templates/users/new.html.erb

<div ng-controller="UsersNewCtrl" class="row">
  <div class="col-md-6 col-md-offset-3">
    <h1 class="text-center">Sign up</h1>
    <form name="userNewForm" novalidate>
      <div class="well">
        <div class="form-group">
          <label>name</label>
          <input name="name" class="form-control"
            ng-model="user.name" required />
        </div>
        <div class="form-group">
          <label>email</label>
          <input type="email" name="email" class="form-control"
            ng-model="user.email" required />
        </div>
        <div class="form-group">
          <label>password</label>
          <input type="password" name="password" class="form-control"
            ng-model="user.password" required />
          </div>
        <div class="form-group">
          <label>password_confirmation</label>
            <input type="password" name="password_confirmation" 
              class="form-control"
              ng-model="user.password_confirmation" required />
        </div>
        <button ng-click="submit()" class="btn btn-primary">
          Create my account
        </button>
      </div>
    </form>
  </div>
</div>

3)AngularJS controller "UsersNewCtrl"

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersNewCtrl", function($scope, userResource) {
  $scope.user = new userResource();
});

4)add a link to home view

$ vi app/assets/templates/static_pages/home.html.erb

<p class="text-center">
  <a class="btn btn-large btn-primary" href="/users/new">Sign up now!</a>
</p>

(3)AngularJS $resource POST

1)AngularJS $resource POST

$ vi app/assets/javascripts/mymodule.js.erb

myModule.factory("userResource", function($resource) {
  return $resource("/app/users/:id", { id: "@id" },
    {
      'create':  { method: 'POST' },
..........
    }
  );
});

mymodule.controller("UsersNewCtrl", function($scope, userResource, $location) {
  $scope.user = new userResource();
  $scope.submit = function() {
    function success(response) {
      $location.path("/users/" + response.id);
    }
    function failure(response) {
      console.log("failure", response)
    }
    userResource.create($scope.user, success, failure);
  };
});

2)Rails controller create action

$ vi app/controllers/users_controller.rb

  def create
    @user = User.new(user_params)
    if @user.save
      render json: @user, status: :created, location: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

private
  def user_params
    params.permit(:name:email,:password,:password_confirmation)
  end

3)CSRF

*Problem

Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 1ms

*Avoidance

$ vi app/assets/javascripts/mymodule.js.erb

myModule.config(function($httpProvider) {
  $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
});

4)test operation

1.home view
2.click "Sign up now!"
3.user sign up
4.user's profile view

Ruby on Rails Tutorial AngularJS $resource, server-side data

1)Rails model, migration, test data

1.Rails model

$ rails generate model User name:string email:string

2.migration

$ rake db:migrate

3.test data

$ rails c

User.create(name: "testuser1", email: "test1@example.com")
User.create(name: "testuser2", email: "test2@example.com")
User.create(name: "testuser3", email: "test3@example.com")

2)Rails controller

1.generate controller

$ rails generate controller Users

2.index action

$ vi app/controllers/users_controller.rb

  def index
    @users = User.all
    render json: @users
  end

3)Rails resource route

$ vi config/routes.rb

  scope '/app' do
    resources :users
  end

4)AngularJS $resource

1.angular-resource include

$ vi app/assets/javascripts/application.js

//= require angular-resource

2.ngResource DI

$ vi app/assets/javascripts/mymodule.js.erb

myModule = angular.module('myModule', ['ui.bootstrap','ngRoute','ngResource']);

5)AngularJS route

1.confirm Rails route

$ rake routes
users GET    /app/users(.:format)           users#index

2.AngularJS route

$ vi app/assets/javascripts/mymodule.js.erb

 .when("/users", {
  templateUrl: "<%= asset_path('users/index.html.erb') %>"
  })

6)AngularJS user index controller

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersIndexCtrl", function($scope,$resource) {
  var rtn = $resource('/app/users');
  $scope.users = rtn.query();
});

7)AngularJS index template view

$ vi app/assets/templates/users/index.html.erb

<div ng-controller="UsersIndexCtrl">
<h1>index</h1>
<table class="table table-bordered">
  <thead>
    <td>name</td>
    <td>email</td>
  </thead>
  <tbody>
    <tr ng-repeat="user in users">
      <td>
        {{user.name}}
      </td>
      <td>
        {{user.email}}
      </td>
    </tr>
  </tbody>
</table>
</div>

8)add link to user index

$ vi app/views/layouts/_header.html.erb

<li><%= link_to "Index", "/users" %></li>

9)Rails route

*Problem

1."http://localhost:3000/users"
2.browser reload
3."No route" error

*Avoidance

$ vi config/routes.rb

get 'users', to: 'layouts#index'