Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add user following
  • Loading branch information
rcb09003 committed Nov 19, 2013
1 parent c9fa5d8 commit 4f2f615
Show file tree
Hide file tree
Showing 20 changed files with 260 additions and 27 deletions.
29 changes: 29 additions & 0 deletions app/assets/stylesheets/static_pages.css.scss
Expand Up @@ -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 { #error_explanation {
color: #f00; color: #f00;
ul { ul {
Expand Down
21 changes: 21 additions & 0 deletions 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
21 changes: 20 additions & 1 deletion app/controllers/users_controller.rb
@@ -1,5 +1,6 @@
class UsersController < ApplicationController 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 :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy before_action :admin_user, only: :destroy


Expand Down Expand Up @@ -40,8 +41,26 @@ class UsersController < ApplicationController
render 'edit' render 'edit'
end end
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 private




def user_params def user_params
params.require(:user).permit(:name, :email, :password, params.require(:user).permit(:name, :email, :password,
:password_confirmation) :password_confirmation)
Expand Down
11 changes: 10 additions & 1 deletion app/models/micropost.rb
Expand Up @@ -4,4 +4,13 @@ class Micropost < ActiveRecord::Base
default_scope -> { order('created_at DESC') } default_scope -> { order('created_at DESC') }
validates :content, presence: true, length: { maximum: 140 } validates :content, presence: true, length: { maximum: 140 }
validates :user_id, presence: true validates :user_id, presence: true
end

# 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
6 changes: 6 additions & 0 deletions 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
25 changes: 23 additions & 2 deletions app/models/user.rb
@@ -1,5 +1,14 @@
class User < ActiveRecord::Base class User < ActiveRecord::Base
has_many :microposts, dependent: :destroy 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_save { self.email = email.downcase }
before_create :create_remember_token before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 } validates :name, presence: true, length: { maximum: 50 }
Expand All @@ -19,8 +28,19 @@ class User < ActiveRecord::Base
end end


def feed def feed
# This is preliminary. See "Following users" for the full implementation. Micropost.from_users_followed_by(self)
Micropost.where("user_id = ?", id) 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 end


private private
Expand All @@ -29,3 +49,4 @@ class User < ActiveRecord::Base
self.remember_token = User.encrypt(User.new_remember_token) self.remember_token = User.encrypt(User.new_remember_token)
end end
end end

2 changes: 2 additions & 0 deletions app/views/relationships/create.js.erb
@@ -0,0 +1,2 @@
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= @user.followers.count %>')
2 changes: 2 additions & 0 deletions app/views/relationships/destroy.js.erb
@@ -0,0 +1,2 @@
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= @user.followers.count %>')
15 changes: 15 additions & 0 deletions app/views/shared/_stats.html.erb
@@ -0,0 +1,15 @@
<% @user ||= current_user %>
<div class="stats">
<a href="<%= following_user_path(@user) %>">
<strong id="following" class="stat">
<%= @user.followed_users.count %>
</strong>
following
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id="followers" class="stat">
<%= @user.followers.count %>
</strong>
followers
</a>
</div>
3 changes: 3 additions & 0 deletions app/views/static_pages/home.html.erb
Expand Up @@ -3,6 +3,9 @@
<aside class="span4"> <aside class="span4">
<section> <section>
<%= render 'shared/user_info' %> <%= render 'shared/user_info' %>
</section>
<section>
<%= render 'shared/stats' %>
</section> </section>
<section> <section>
<%= render 'shared/micropost_form' %> <%= render 'shared/micropost_form' %>
Expand Down
5 changes: 5 additions & 0 deletions app/views/users/_follow.html.erb
@@ -0,0 +1,5 @@
<%= form_for(current_user.relationships.build(followed_id: @user.id),
remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
9 changes: 9 additions & 0 deletions app/views/users/_follow_form.html.erb
@@ -0,0 +1,9 @@
<% unless current_user?(@user) %>
<div id="follow_form">
<% if current_user.following?(@user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
5 changes: 5 additions & 0 deletions app/views/users/_unfollow.html.erb
@@ -0,0 +1,5 @@
<%= form_for(current_user.relationships.find_by(followed_id: @user),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
6 changes: 6 additions & 0 deletions app/views/users/show.html.erb
Expand Up @@ -6,9 +6,15 @@
<%= gravatar_for @user %> <%= gravatar_for @user %>
<%= @user.name %> <%= @user.name %>
</h1> </h1>
</section>
<section>
<%= render 'shared/stats' %>
</section> </section>
</aside> </aside>

<div class="span8"> <div class="span8">
<%= render 'follow_form' if signed_in? %>
<% if @user.microposts.any? %> <% if @user.microposts.any? %>
<h3>Microposts (<%= @user.microposts.count %>)</h3> <h3>Microposts (<%= @user.microposts.count %>)</h3>
<ol class="microposts"> <ol class="microposts">
Expand Down
30 changes: 30 additions & 0 deletions app/views/users/show_follow.html.erb
@@ -0,0 +1,30 @@
<% provide(:title, @title) %>
<div class="row">
<aside class="span4">
<section>
<%= 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>
<%= 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="span8">
<h3><%= @title %></h3>
<% if @users.any? %>
<ul class="users">
<%= render @users %>
</ul>
<%= will_paginate %>
<% end %>
</div>
</div>
6 changes: 6 additions & 0 deletions config/routes.rb
@@ -1,8 +1,14 @@
SampleApp::Application.routes.draw do SampleApp::Application.routes.draw do
resources :users do
member do
get :following, :followers
end
end
resources :products resources :products
resources :users resources :users
resources :sessions, only: [:new, :create, :destroy] resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy] resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
root 'static_pages#home' root 'static_pages#home'
match '/signup', to: 'users#new', via: 'get' match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get' match '/signin', to: 'sessions#new', via: 'get'
Expand Down
13 changes: 13 additions & 0 deletions db/migrate/20131118215946_create_relationships.rb
@@ -0,0 +1,13 @@
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
13 changes: 12 additions & 1 deletion db/schema.rb
Expand Up @@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.


ActiveRecord::Schema.define(version: 20131107052554) do ActiveRecord::Schema.define(version: 20131118215946) do


create_table "microposts", force: true do |t| create_table "microposts", force: true do |t|
t.string "content" t.string "content"
Expand All @@ -29,6 +29,17 @@ ActiveRecord::Schema.define(version: 20131107052554) do
t.datetime "updated_at" t.datetime "updated_at"
end end


create_table "relationships", force: true do |t|
t.integer "follower_id"
t.integer "followed_id"
t.datetime "created_at"
t.datetime "updated_at"
end

add_index "relationships", ["followed_id"], name: "index_relationships_on_followed_id"
add_index "relationships", ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true
add_index "relationships", ["follower_id"], name: "index_relationships_on_follower_id"

create_table "users", force: true do |t| create_table "users", force: true do |t|
t.string "name" t.string "name"
t.string "email" t.string "email"
Expand Down
60 changes: 38 additions & 22 deletions lib/tasks/sample_data.rake
@@ -1,26 +1,42 @@
namespace :db do namespace :db do

desc "Fill database with sample data" desc "Fill database with sample data"
task populate: :environment do task populate: :environment do

make_users
User.create!(name: "Example User", make_microposts
email: "example@railstutorial.org", make_relationships
password: "foobar", end
password_confirmation: "foobar") end
99.times do |n|
name = Faker::Name.name def make_users
email = "example-#{n+1}@railstutorial.org" admin = User.create!(name: "Example User",
password = "password" email: "example@railstutorial.org",
User.create!(name: name, password: "foobar",
email: email, password_confirmation: "foobar",
password: password, admin: true)
password_confirmation: password) 99.times do |n|
end name = Faker::Name.name
users = User.all(limit: 6) email = "example-#{n+1}@railstutorial.org"
50.times do password = "password"
content = Faker::Lorem.sentence(5) User.create!(name: name,
users.each { |user| user.microposts.create!(content: content) } email: email,
end password: password,
end password_confirmation: password)
end
end end


def make_microposts
users = User.all(limit: 6)
50.times do
content = Faker::Lorem.sentence(5)
users.each { |user| user.microposts.create!(content: content) }
end
end

def make_relationships
users = User.all
user = users.first
followed_users = users[2..50]
followers = users[3..40]
followed_users.each { |followed| user.follow!(followed) }
followers.each { |follower| follower.follow!(user) }
end
5 changes: 5 additions & 0 deletions spec/models/relationship_spec.rb
@@ -0,0 +1,5 @@
require 'spec_helper'

describe Relationship do
pending "add some examples to (or delete) #{__FILE__}"
end

0 comments on commit 4f2f615

Please sign in to comment.