- AngularJS : 1.6.5
- Bootstrap : 3.x
- UI Bootstrap : 2.5.0
Google Maps,AngularJS
1)Rails route
$ vi config/routes.rb
match '/app/relationships', to: 'relationships#create', via: 'post' match '/app/relationships', to: 'relationships#destroy', via: 'delete'
2)Rails controller
$ vi app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController before_action :signed_in_user def create remember_token = User.encrypt(cookies[:remember_token]) current_user ||= User.find_by(remember_token: remember_token) @user = User.find(user_params[:id]) current_user.follow!(@user) head :no_content end def destroy remember_token = User.encrypt(cookies[:remember_token]) current_user ||= User.find_by(remember_token: remember_token) @user = User.find(user_params[:id]) current_user.unfollow!(@user) head :no_content end private def user_params params.permit(:id) end def signed_in_user remember_token = User.encrypt(cookies[:remember_token]) current_user ||= User.find_by(remember_token: remember_token) if current_user.nil? render status: :unauthorized end end end
3)AngularJS "relationshipsResource" service
$ vi app/assets/javascripts/mymodule.js.erb
myModule.factory("relationshipsResource", function($resource) { return $resource("/app/relationships",{}, { 'create': { method: 'POST' }, 'destroy': { method: 'DELETE' } } ); });
4)AngularJS controller
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("UsersShowCtrl", function($scope, $routeParams, userResource, flashService, $filter, micropostsResource, $q, sessionResource, relationshipsResource) { ..... $scope.follow = function(id) { function success(response) { $scope.flg_unfollow = true; sessionResource.current_user({}, function(response) { flashService.setUser(response); }); $scope.$emit("$routeChangeSuccess"); } function failure(response) { console.log("follow error"); } var user_data = { id: id }; relationshipsResource.create(user_data, success, failure); }; $scope.unfollow = function(id) { relationshipsResource.destroy({ id: id }, function(response) { $scope.flg_unfollow = false; sessionResource.current_user({}, function(response) { flashService.setUser(response); }); $scope.$emit("$routeChangeSuccess"); }); };
1)AngularJS template view
$ vi app/assets/templates/users/show.html.erb
<div class="col-xs-6 col-sm-8"> <div ng-show="!flg_follers && chkSignin() && chkSignin().user.id != user_info.user.id" class="row"> <div ng-show="flg_unfollow"> <a class="btn btn-large btn-primary" href="#" ng-click="unfollow(user_info.user.id)"> Unfollow </a> </div> <div ng-hide="flg_unfollow"> <a class="btn btn-large btn-primary" href="#" ng-click="follow(user_info.user.id)">follow</a> </div> </div>
2)AngularJS controller
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("UsersShowCtrl", function($scope, $routeParams, userResource, flashService, $filter, micropostsResource, $q) { var qgetUser = function(deferred) { if (flashService.getUser()) { var quser_info = flashService.getUser(); deferred.resolve(quser_info); } else { sessionResource.current_user({}, function(response) { if (response.user.id) { var quser_info = response; } else { var quser_info = { user: {id: 0} }; } flashService.setUser(quser_info); deferred.resolve(quser_info); }); } } var chkUnfollow = function() { $scope.flg_unfollow = false; var deferred = $q.defer(); deferred.promise.then(function (result) { var user_signin = result.user.id; for (var i=0; i<=$scope.user_info.followers.length; i++) { if ($scope.user_info.followers[i] && $scope.user_info.followers[i].id == user_signin) { $scope.flg_unfollow = true; } } },function (reason) { console.log("user_signin-Error"); },function (reason) { console.log("user_signin"); }) qgetUser(deferred); }; userResource.show({ id: $routeParams.id }, function(response) { $scope.user_info = response; chkUnfollow(); ........ });
(1)Home page
1)follower stats parts
$ vi app/assets/templates/static_pages/home.html.erb
<div class="stats"> <a href="#" ng-click="following()"> <strong id="following" class="stat"> {{chkSignin().followed_users.length}} </strong> following </a> <a href="#"> <strong id="followers" class="stat"> {{chkSignin().followers.length}} </strong> followers </a> </div>
2)following and followers list parts
$ vi app/assets/templates/static_pages/home.html.erb
..... <div class="col-sm-8"> <div ng-show="flg_follers" class="row"> <h1 class="text-center">{{follow_title}}</h1> <ul ng-repeat="f_user in f_users" class="users"> <li><img alt="{{f_user.name}}" src="https://secure.gravatar.com/avatar/{{hash(f_user.email)}}?s=52" /> <a href="/users/{{f_user.id}}">{{f_user.name}}</a> </li> </ul> </div> <h3>Micropost Feed</h3> .....
3)AngularJS controller
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("HomeCtrl", function($scope, flashService, micropostsResource, sessionResource, $filter) { ..... $scope.chkSignin = function() { return flashService.getUser(); }; ..... $scope.flg_follers = false; $scope.following = function() { $scope.flg_follers = true; $scope.follow_title = "Following"; $scope.f_users = $scope.chkSignin().followed_users; }; $scope.followers = function() { $scope.flg_follers = true; $scope.follow_title = "Followers"; $scope.f_users = $scope.chkSignin().followers; }; $scope.hash = function(email) { return md5(email.toLowerCase()); };
(2)User Profile page
1)follower stats parts
$ 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}}?s=60" class="gravatar" /> {{user_info.user.name}} </h3> <span ng-show="flg_follers"> <a href="#" ng-click="viewProfile()"> view my profile </a> </span><br /> <div class="stats"> <a href="#" ng-click="following()"> <strong id="following" class="stat"> {{user_info.followed_users.length}} </strong> following </a> <a href="#" ng-click="followers()"> <strong id="followers" class="stat"> {{user_info.followers.length}} </strong> followers </a> </div> </div>
2)following and followers list parts
$ vi app/assets/templates/users/show.html.erb
<div class="col-xs-6 col-sm-8"> <div ng-show="flg_follers" class="row"> <h3>{{follow_title}}</h3> <ul ng-repeat="f_user in f_users" class="users"> <li><img alt="{{f_user.name}}" src="https://secure.gravatar.com/avatar/{{hash(f_user.email)}}?s=52" /> <a href="/users/{{f_user.id}}">{{f_user.name}}</a> </li> </ul> </div> <div ng-hide="flg_follers" class="row"> <h3>Microposts({{user_info.microposts.length}})</h3> .......
3)AngularJS controller
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("UsersShowCtrl", function($scope, $routeParams, userResource, flashService, $filter, micropostsResource, $q) { ..... userResource.show({ id: $routeParams.id }, function(response) { $scope.user_info = response; ....... }); $scope.flg_follers = false; $scope.following = function() { $scope.flg_follers = true; $scope.follow_title = "Following"; $scope.f_users = $scope.user_info.followed_users; }; $scope.followers = function() { $scope.flg_follers = true; $scope.follow_title = "Followers"; $scope.f_users = $scope.user_info.followers; }; $scope.viewProfile = function() { $scope.flg_follers = false; }; $scope.hash = function(email) { return md5(email.toLowerCase()); };
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>
(1)Rails model, association, validation
1)"Relationship" model
$ rails generate model Relationship follower_id:integer followed_id:integer
2)add indices for the relationships table
$ vi db/migrate/…._create_relationships.rb
class CreateRelationships < ActiveRecord::Migration def change create_table :relationships do |t| t.integer :follower_id t.integer :followed_id t.timestamps end add_index :relationships, :follower_id add_index :relationships, :followed_id add_index :relationships, [:follower_id, :followed_id], unique: true end end
3)migrate
$ bundle exec rake db:migrate
4)validation
$ vi app/models/relationship.rb
validates :follower_id, presence: true validates :followed_id, presence: true
(2)User/followed_users associations
1)"relationship" model
$ vi app/models/relationship.rb
belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User"
2)"user" model
$ vi app/models/user.rb
has_many :relationships, foreign_key: "follower_id", dependent: :destroy has_many :followed_users, through: :relationships, source: :followed
3)Utility methods for following
$ vi app/models/user.rb
def following?(other_user) relationships.find_by(followed_id: other_user.id) end def follow!(other_user) relationships.create!(followed_id: other_user.id) end def unfollow!(other_user) relationships.find_by(followed_id: other_user.id).destroy end
(3)User/followers associations
1)"relationship" model
$ more app/models/relationship.rb
belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User"
2)"user" model
$ vi app/models/user.rb
has_many :reverse_relationships, foreign_key: "followed_id", class_name: "Relationship", dependent: :destroy has_many :followers, through: :reverse_relationships, source: :follower
(3)check by console
1.user instance
> user2=User.find_by(id: 2)
> user6=User.find_by(id: 6)
2."following?"
> user2.following?(user6)
=> nil
> user6.following?(user2)
=> nil
3."follow!"
> user2.follow!(user6)
(0.2ms) begin transaction
SQL (0.3ms) INSERT INTO "relationships" ("created_at", "followed_id", "follower_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-07-24 08:17:13.716171"], ["followed_id", 6], ["follower_id", 2], ["updated_at", "2015-07-24 08:17:13.716171"]]
(3.4ms) commit transaction
=> #<Relationship id: 1, follower_id: 2, followed_id: 6, created_at: "2015-07-24 08:17:13", updated_at: "2015-07-24 08:17:13">
> user6.follow!(user2)
4."relationships", "reverse_relationships" association
> user2.relationships
=> #<ActiveRecord::Associations::CollectionProxy [#<Relationship id: 1, follower_id: 2, followed_id: 6, created_at: "2015-07-24 08:17:13", updated_at: "2015-07-24 08:17:13">]>
> user2.reverse_relationships
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."followed_id" = ? [["followed_id", 2]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Relationship id: 2, follower_id: 6, followed_id: 2, created_at: "2015-07-24 08:17:54", updated_at: "2015-07-24 08:17:54">]>
> Relationship.all
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships"
=> #<ActiveRecord::Relation [#<Relationship id: 1, follower_id: 2, followed_id: 6, created_at: "2015-07-24 08:17:13", updated_at: "2015-07-24 08:17:13">, #<Relationship id: 2, follower_id: 6, followed_id: 2, created_at: "2015-07-24 08:17:54", updated_at: "2015-07-24 08:17:54">]>
> user2.relationships.find_by(followed_id: user6)
Relationship Load (0.1ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = 6 LIMIT 1 [["follower_id", 2]]
=> #<Relationship id: 1, follower_id: 2, followed_id: 6, created_at: "2015-07-24 08:17:13", updated_at: "2015-07-24 08:17:13">
5."followed_users", "followers" association
> user2.followed_users.count
=> 1
> user2.followers.count
=> 1
> user6.followed_users.count
=> 1
> user6.followers.count
=> 1
> user2.followers.all
> user2.followed_users.all
(4)show following and followers
1)Rails 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)) 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, feed: user.feed, followed_users: user.followed_users, followers: user.followers } render json: @user_info, status: :accepted, location: user else ...... def current_user remember_token = User.encrypt(cookies[:remember_token]) current_user ||= User.find_by(remember_token: remember_token) if current_user gravatar_id = Digest::MD5::hexdigest(current_user.email.downcase) microposts = current_user.microposts @user_info = { user: current_user, gravatar_url: "https://secure.gravatar.com/avatar/#{gravatar_id}", microposts: microposts, feed: current_user.feed, followed_users: current_user.followed_users, followers: current_user.followers } render json: @user_info, status: :accepted else head :no_content end end
2)AngularJS template view
$ vi app/assets/templates/static_pages/home.html.erb
<div ng-controller="HomeCtrl"> <div ng-show="chkSignin().user.id > 0" class="row"> ...... <div class="col-sm-4"> ......... <div class="stats"> <a href="#"> <strong id="following" class="stat"> {{chkSignin().followed_users.length}} </strong> following </a> <a href="#"> <strong id="followers" class="stat"> {{chkSignin().followers.length}} </strong> followers </a> </div>
3)css
$ vi app/assets/stylesheets/custom.css.scss
.stats { overflow: auto; border-top: 1px solid $grayLighter; a { float: left; padding: 0 10px; border-left: 1px solid $grayLighter; color: gray; &:first-child { padding-left: 0; border: 0; } &:hover { text-decoration: none; color: blue; } } strong { display: block; } }
(1)Rails controller
$ vi app/controllers/microposts_controller.rb
before_action :signed_in_user, only: [:create, :destroy] before_action :correct_user, only: :destroy def destroy Micropost.find(params[:id]).destroy head :no_content end
(2)add link to views
$ vi app/assets/templates/static_pages/home.html.erb
$ vi app/assets/templates/users/show.html.erb
..... <small class="text-muted">Posted {{mp.created_at | date:'medium'}}</sm all> <span ng-show="chkSignin().user.id == mp.user_id"><a href="" ng-click="delete(mp.id)">delete</a></span> .....
(3)AngularJS controller
1)User Profile page "UsersShowCtrl" controller
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("UsersShowCtrl", function($scope, $routeParams, userResource,flashService,micropostsResource) { $scope.chkSignin = function() { return flashService.getUser(); }; $scope.delete = function(id) { micropostsResource.destroy({ id: id }); userResource.show({ id: $routeParams.id }, function(response) { $scope.user_info = response; $scope.totalitems = $scope.user_info.microposts.length; microposts = $filter('orderBy')($scope.user_info.microposts,'created_at',true); $scope.currentitems = microposts.slice(start,end); flashService.setUser(response); }); }; });
2)Home page "HomeCtrl" controller
$scope.delete = function(id) { micropostsResource.destroy({ id: id }); sessionResource.current_user({}, function(response) { tmp_feed = response.feed; $scope.totalitems = tmp_feed.length; feed_items = $filter('orderBy')(tmp_feed,'created_at',true); $scope.currentitems = feed_items.slice(start,end); flashService.setUser(response); }); };
1)AngularJS template view
$ vi app/assets/templates/static_pages/home.html.erb
<div ng-controller="HomeCtrl"> <div ng-show="chkSignin().user.id > 0" class="row"> <div class="col-sm-4"> ....... </div> <div class="col-sm-8"> <h3>Micropost Feed</h3> <ol class="microposts"> <li ng-repeat="mp in currentitems"> ........... </li> </ol> <pagination total-items="totalitems" ng-model="currentpage" max-size="maxsize" items-per-page="itemsperpage" class="pagination-sm" previous-text="Previous" next-text="Next" first-text="First" last-text="Last" boundary-links="true"> </pagination> </div> </div>
2)AngularJS controller
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("HomeCtrl", function($scope, flashService, micropostsResource, sessionResource, $filter) { .... $scope.submit = function() { function success(response) { sessionResource.current_user({}, function(response1) { var current_user = response1; $scope.totalitems = current_user.feed.length; feed_items = $filter('orderBy')(current_user.feed,'created_at',true); $scope.currentitems = feed_items.slice(start,end); flashService.setUser(current_user); }); flashService.push(msg); $scope.$emit("$routeChangeSuccess"); } function failure(response) { ........ } micropostsResource.create($scope.micropost, success, failure); }; ......... var feed_items = []; $scope.maxsize = 5; $scope.itemsperpage = 8; $scope.currentpage = 1; var start = 0; var end = start + $scope.itemsperpage; sessionResource.current_user({}, function(response) { if (response.feed) { var tmp_feed = response.feed; $scope.totalitems = tmp_feed.length; feed_items = $filter('orderBy')(tmp_feed,'created_at',true); $scope.currentitems = feed_items.slice(start,end); } }); $scope.$watch('currentpage', function() { start = ($scope.currentpage - 1) * $scope.itemsperpage; end = start + $scope.itemsperpage; $scope.currentitems = feed_items.slice(start,end); },true); });