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