diff --git a/app/assets/stylesheets/static_pages.css.scss b/app/assets/stylesheets/static_pages.css.scss index 0408814..9a85153 100644 --- a/app/assets/stylesheets/static_pages.css.scss +++ b/app/assets/stylesheets/static_pages.css.scss @@ -139,6 +139,35 @@ aside { } } +.stats { + overflow: auto; + 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; + } +} + +.user_avatars { + overflow: auto; + margin-top: 10px; + .gravatar { + margin: 1px 1px; + } +} + #error_explanation { color: #f00; ul { diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb new file mode 100644 index 0000000..fbadfec --- /dev/null +++ b/app/controllers/relationships_controller.rb @@ -0,0 +1,21 @@ +class RelationshipsController < ApplicationController + before_action :signed_in_user + + def create + @user = User.find(params[:relationship][:followed_id]) + current_user.follow!(@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) + respond_to do |format| + format.html { redirect_to @user } + format.js + end + end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6b7b828..8ffd160 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,5 +1,6 @@ class UsersController < ApplicationController - before_action :signed_in_user, only: [:index, :edit, :update, :destroy] + before_action :signed_in_user, + only: [:index, :edit, :update, :destroy, :following, :followers] before_action :correct_user, only: [:edit, :update] before_action :admin_user, only: :destroy @@ -40,8 +41,26 @@ class UsersController < ApplicationController render 'edit' end end + + def following + @title = "Following" + @user = User.find(params[:id]) + @users = @user.followed_users.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 + + def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) diff --git a/app/models/micropost.rb b/app/models/micropost.rb index de034b6..057dca3 100644 --- a/app/models/micropost.rb +++ b/app/models/micropost.rb @@ -4,4 +4,13 @@ class Micropost < ActiveRecord::Base default_scope -> { order('created_at DESC') } validates :content, presence: true, length: { maximum: 140 } validates :user_id, presence: true -end \ No newline at end of file + + + # Returns microposts from the users being followed by the given user. + def self.from_users_followed_by(user) + followed_user_ids = "SELECT followed_id FROM relationships + WHERE follower_id = :user_id" + where("user_id IN (#{followed_user_ids}) OR user_id = :user_id", + user_id: user.id) + end +end diff --git a/app/models/relationship.rb b/app/models/relationship.rb new file mode 100644 index 0000000..f900f25 --- /dev/null +++ b/app/models/relationship.rb @@ -0,0 +1,6 @@ +class Relationship < ActiveRecord::Base + belongs_to :follower, class_name: "User" + belongs_to :followed, class_name: "User" + validates :follower_id, presence: true + validates :followed_id, presence: true +end diff --git a/app/models/user.rb b/app/models/user.rb index c4128b1..00e46ac 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,14 @@ class User < ActiveRecord::Base has_many :microposts, dependent: :destroy + + has_many :relationships, foreign_key: "follower_id", dependent: :destroy + has_many :followed_users, through: :relationships, source: :followed + + has_many :reverse_relationships, foreign_key: "followed_id", + class_name: "Relationship", + dependent: :destroy + has_many :followers, through: :reverse_relationships, source: :follower + before_save { self.email = email.downcase } before_create :create_remember_token validates :name, presence: true, length: { maximum: 50 } @@ -19,8 +28,19 @@ class User < ActiveRecord::Base end def feed - # This is preliminary. See "Following users" for the full implementation. - Micropost.where("user_id = ?", id) + Micropost.from_users_followed_by(self) + end + + 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 private @@ -29,3 +49,4 @@ class User < ActiveRecord::Base self.remember_token = User.encrypt(User.new_remember_token) end end + diff --git a/app/views/relationships/create.js.erb b/app/views/relationships/create.js.erb new file mode 100644 index 0000000..d5509e8 --- /dev/null +++ b/app/views/relationships/create.js.erb @@ -0,0 +1,2 @@ +$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>") +$("#followers").html('<%= @user.followers.count %>') \ No newline at end of file diff --git a/app/views/relationships/destroy.js.erb b/app/views/relationships/destroy.js.erb new file mode 100644 index 0000000..fa23b16 --- /dev/null +++ b/app/views/relationships/destroy.js.erb @@ -0,0 +1,2 @@ +$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>") +$("#followers").html('<%= @user.followers.count %>') \ No newline at end of file diff --git a/app/views/shared/_stats.html.erb b/app/views/shared/_stats.html.erb new file mode 100644 index 0000000..e68c491 --- /dev/null +++ b/app/views/shared/_stats.html.erb @@ -0,0 +1,15 @@ +<% @user ||= current_user %> +