Commit 2689d50b by Quang Vinh Nguyen

Add user following

parent a16dd18f
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
......@@ -164,6 +164,45 @@ aside {
margin-top: 15px;
}
.stats {
overflow: auto;
margin-top: 0;
padding: 0;
a {
float: left;
padding: 0 10px;
border-left: 1px solid $gray-lighter;
color: gray;
&:first-child {
padding-left: 0;
border: 0;
}
&:hover {
text-decoration: none;
color: blue;
}
}
strong {
display: block;
}
}
.user_avatars {
overflow: auto;
margin-top: 10px;
.gravatar {
margin: 1px 1px;
}
a {
padding: 0;
}
}
.users.follow {
padding: 0;
}
/* forms */
input, textarea, select, .uneditable-input {
border: 1px solid #bbb;
......
// Place all the styles related to the Relationships controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
class RelationshipsController < ApplicationController
before_action :logged_in_user
def create
user = User.find(params[:followed_id])
current_user.follow(user)
# redirect_to user
respond_to do |format|
format.html { redirect_to @user }
format.js
end
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
# redirect_to user
respond_to do |format|
format.html { redirect_to @user }
format.js
end
end
end
......@@ -55,6 +55,20 @@ class UsersController < ApplicationController
redirect_to users_url
end
def following
@title = 'Following'
@user = User.find(params[:id])
@users = @user.following.paginate(page: params[:page])
render 'show_follow'
end
def followers
@title = 'Followers'
@user = User.find(params[:id])
@users = @user.followers.paginate(page: params[:page])
render 'show_follow'
end
private
# comment
......
module RelationshipsHelper
end
class Relationship < ApplicationRecord
belongs_to :follower, class_name: 'User'
belongs_to :followed, class_name: 'User'
validates :follower_id, presence: true
validates :follower_id, presence: true
end
# comment
class User < ApplicationRecord
has_many :microposts, dependent: :destroy
has_many :active_relationships, class_name: 'Relationship',
foreign_key: 'follower_id',
dependent: :destroy
has_many :passive_relationships, class_name: 'Relationship',
foreign_key: 'followed_id',
dependent: :destroy
has_many :following, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
attr_accessor :remember_token, :activation_token, :reset_token # we don't wan't to save this attribute to database
before_save :downcase_email # before_save { email.downcase! }
before_create :create_activation_digest
......@@ -80,7 +89,29 @@ class User < ApplicationRecord
# See 'Following users' for the full implementation.
def feed
Micropost.where('user_id = ?', id) # self.id
# Micropost.where('user_id = ?', id) # self.id
# Micropost.where("user_id IN (?) OR user_id = ? ", following_ids,id)
# Micropost.where("user_id IN (:following_ids) OR user_id = :user_id",
# following_ids: following_ids, user_id: id)
following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
Micropost.where("user_id IN (#{following_ids})
OR user_id = :user_id", user_id: id)
end
# Follows a user.
def follow(other_user)
following << other_user
end
# Unfollows a user.
def unfollow(other_user)
following.delete(other_user)
end
# Returns true if the current user is following the other user.
def following?(other_user)
following.include?(other_user)
end
private
......
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= @user.followers.count %>');
\ No newline at end of file
$("follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("followers").html('<%= @user.followers.count %>');
\ No newline at end of file
<% @user ||= current_user %>
<div class='stats'>
<a href="<%=following_user_path(@user) %>">
<strong id='following' class='stat'>
<%= @user.following.count %>
</strong>
following
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id='followers' class'stat'>
<%= @user.followers.count %>
</strong>
followers
</a>
</div>
\ No newline at end of file
......@@ -6,6 +6,9 @@
<section class='user_infor'>
<%= render 'shared/user_info' %>
</section>
<section class'stats'>
<%= render 'shared/stats' %>
</section>
<section class='micropost_form'>
<%= render 'shared/micropost_form' %>
</section>
......
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, @user.id %></div>
<%= f.submit 'Follow', class: 'btn btn-primary' %>
<% end %>
\ No newline at end of file
<% unless current_user?(@user) %>
<div id='follow_form'>
<% if current_user.following?(@user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
\ No newline at end of file
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
html: { method: :delete }, remote: true ) do |f| %>
<%= f.submit 'Unfollow', class: 'btn' %>
<% end %>
\ No newline at end of file
......@@ -7,9 +7,13 @@
<%= @user.name %>
</h1>
</section>
<section class='stats'>
<%= render 'shared/stats' %>
</section>
</aside>
<div class='col-md-8'>
<%= render 'follow_form' if logged_in? %>
<% if @user.microposts.any? %>
<h3>Microposts (<%= @user.microposts.count %>)</h3>
<ol class='micropost'>
......
<% provide(:title, @title) %>
<div class='row'>
<aside class='col-md-4'>
<section class='user_info'>
<%= gravatar_for @user %>
<h1><%= @user.name %></h1>
<span><%= link_to 'view my profile', @user %></span>
<span><b>Microposts:</b><%= @user.microposts.count %></span>
</section>
<section class='stats'>
<%= render 'shared/stats' %>
<% if @users.any? %>
<div class='user_avatars'>
<% @users.each do |user| %>
<%= link_to gravatar_for(user, size: 30), user %>
<% end %>
</div>
<% end %>
</section>
</aside>
<div class='col-md-8'>
<h3><%= @title %></h3>
<% if @users.any? %>
<ul class='user follow'>
<%= render @users %>
</ul>
<%= will_paginate %>
<% end %>
</div>
</div>
\ No newline at end of file
......@@ -14,5 +14,8 @@ module SampleApp
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Include the authenticity token in remote form.
config.action_view.embed_authenticity_token_in_remote_forms = true
end
end
......@@ -8,8 +8,14 @@ Rails.application.routes.draw do
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
# resources :users
resources :users do
member do
get :following, :followers
end
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
end
class CreateRelationships < ActiveRecord::Migration[5.1]
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
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180605023125) do
ActiveRecord::Schema.define(version: 20180605031002) do
create_table "microposts", force: :cascade do |t|
t.text "content"
......@@ -22,6 +22,16 @@ ActiveRecord::Schema.define(version: 20180605023125) do
t.index ["user_id"], name: "index_microposts_on_user_id"
end
create_table "relationships", force: :cascade do |t|
t.integer "follower_id"
t.integer "followed_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["followed_id"], name: "index_relationships_on_followed_id"
t.index ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true
t.index ["follower_id"], name: "index_relationships_on_follower_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
......
......@@ -21,11 +21,22 @@ User.create!(name: 'Example User',
User.create!(name: name,
email: email,
password: password,
password_confirmation: password)
password_confirmation: password,
activated: true,
activated_at: Time.zone.now)
end
# Microposts
users = User.order(:created_at).take(6)
50.times do
content = Faker::Lorem.sentence(5)
users.each { |user| user.microposts.create!(content: content) }
end
# Following relatioships
users = User.all
user = users.first
following = users[2..50]
followers = users[3..40]
following.each { |followed| user.follow(followed) }
followers.each { |follower| follower.follow(user) }
require 'test_helper'
class RelationshipsControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
follower_id: 1
followed_id: 1
two:
follower_id: 1
followed_id: 1
require 'test_helper'
class RelationshipTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment