(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; } }