Permalink
Browse files

Add user following.

  • Loading branch information...
1 parent 1e4dfbc commit 9925dddadcb2ec32b0bffa4e3dc96d6d95f554a2 @sophiaxc committed Apr 29, 2012
View
14 :w
@@ -1,14 +0,0 @@
-<% provide(:title, "Sign in") %>
-<h1>Sign in</h1>
-
-<div class="row">
- <div class="span6 offset3">
- <%= form_for(:session, url: sessions_path) do |f| %>
-
- <%= f.label :email %>
- <%= f.text_field :email %>
-
- <%= f.label :password %>
- <%= f.password_field :password %>
-
- <%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
@@ -136,6 +136,36 @@ aside {
margin-right: 10px;
}
+.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;
+ }
+}
+
+
/* miscellaneous */
.debug_dump {
@@ -0,0 +1,21 @@
+class RelationshipsController < ApplicationController
+ before_filter :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
@@ -1,8 +1,23 @@
class UsersController < ApplicationController
- before_filter :signed_in_user, only: [:index, :edit, :update]
+ before_filter :signed_in_user,
+ only: [:index, :edit, :update, :destroy, :following, :followers]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
+ def followers
+ @title = "Followers"
+ @user = User.find(params[:id])
+ @users = @user.followers.paginate(page: params[:page])
+ render 'show_follow'
+ end
+
+ def following
+ @title = "Following"
+ @user = User.find(params[:id])
+ @users = @user.followed_users.paginate(page: params[:page])
+ render 'show_follow'
+ end
+
def index
@users = User.paginate(page: params[:page])
end
@@ -18,4 +18,20 @@ class Grampost < ActiveRecord::Base
validates :title, presence: true, length: { maximum: 140 }
default_scope order: 'gramposts.created_at DESC'
+ scope :from_users_followed_by, lambda { |user| followed_by(user) }
+
+ private
+
+ # Returns an SQL condition for users followed by the given user.
+ # We include the user's own id as well.
+ def self.followed_by(user)
+ if user.followed_user_ids.empty?
+ where("user_id = ?", user)
+ else
+ 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 })
+ end
+ end
end
@@ -0,0 +1,9 @@
+class Relationship < ActiveRecord::Base
+ attr_accessible :followed_id
+
+ belongs_to :follower, class_name: "User"
+ belongs_to :followed, class_name: "User"
+
+ validates :follower_id, presence: true
+ validates :followed_id, presence: true
+end
View
@@ -16,6 +16,12 @@ class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :gramposts, dependent: :destroy
+ has_many :relationships, foreign_key: "follower_id", dependent: :destroy
+ has_many :reverse_relationships, foreign_key: "followed_id",
+ class_name: "Relationship",
+ dependent: :destroy
+ has_many :followed_users, through: :relationships, source: :followed
+ has_many :followers, through: :reverse_relationships, source: :follower
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
@@ -29,7 +35,19 @@ class User < ActiveRecord::Base
validates :password_confirmation, presence: true
def feed
- Grampost.where("user_id = ?", id)
+ Grampost.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
@@ -0,0 +1,2 @@
+$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
+$("#followers").html('<%= @user.followers.count %>')
@@ -0,0 +1,2 @@
+$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
+$("#followers").html('<%= @user.followers.count %>')
@@ -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>
@@ -5,6 +5,9 @@
<%= render 'shared/user_info' %>
</section>
<section>
+ <%= render 'shared/stats' %>
+ </section>
+ <section>
<%= render 'shared/grampost_form' %>
</section>
</aside>
@@ -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 %>
@@ -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 %>
@@ -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 %>
@@ -7,8 +7,12 @@
<%= @user.name %>
</h1>
</section>
+ <section>
+ <%= render 'shared/stats' %>
+ </section>
</aside>
<div class="span8">
+ <%= render 'follow_form' if signed_in? %>
<% if @user.gramposts.any? %>
<h3>Gramposts</h3>
<ol class="gramposts">
@@ -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>Gramposts:</b> <%= @user.gramposts.count %></span>
+ </section>
+ <section>
+ <%= render 'shared/stats' %>
+ <% unless @users.empty? %>
+ <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 @users %>
+ <% end %>
+ </div>
+</div>
View
@@ -1,7 +1,12 @@
Gramlist::Application.routes.draw do
- resources :users
resources :sessions, only: [:new, :create, :destroy]
+ resources :relationships, only: [:create, :destroy]
resources :gramposts, only: [:create, :destroy, :index]
+ resources :users do
+ member do
+ get :following, :followers
+ end
+ end
root to: 'static_pages#home'
match '/signup', to: 'users#new'
@@ -0,0 +1,14 @@
+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, :followed_id
+ add_index :relationships, :follower_id
+ add_index :relationships, [:follower_id, :followed_id], unique: true
+ end
+end
View
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20120424042957) do
+ActiveRecord::Schema.define(:version => 20120429193500) do
create_table "gramposts", :force => true do |t|
t.string "title"
@@ -23,6 +23,17 @@
add_index "gramposts", ["user_id", "created_at"], :name => "index_gramposts_on_user_id_and_created_at"
+ create_table "relationships", :force => true do |t|
+ t.integer "follower_id"
+ t.integer "followed_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ 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|
t.string "name"
t.string "email"
@@ -1,27 +1,43 @@
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
- admin = User.create!(name: "Example User",
- email: "example@railstutorial.org",
- password: "foobar",
- password_confirmation: "foobar")
- admin.toggle!(:admin)
- 99.times do |n|
- name = Faker::Name.name
- email = "example-#{n+1}@railstutorial.org"
- password = "password"
- User.create!(name: name,
- email: email,
- password: password,
- password_confirmation: password)
- end
+ make_users
+ make_gramposts
+ make_relationships
+ end
+end
- users = User.all(limit: 6)
- 50.times do
- title = Faker::Lorem.sentence(2)
- description = Faker::Lorem.sentence(5)
- users.each { |user| user.gramposts.create!(title: title,
- description: description) }
- end
+def make_users
+ admin = User.create!(name: "Example User",
+ email: "example@railstutorial.org",
+ password: "foobar",
+ password_confirmation: "foobar")
+ admin.toggle!(:admin)
+ 99.times do |n|
+ name = Faker::Name.name
+ email = "example-#{n+1}@railstutorial.org"
+ password = "password"
+ User.create!(name: name,
+ email: email,
+ password: password,
+ password_confirmation: password)
end
end
+
+def make_gramposts
+ users = User.all(limit: 6)
+ 50.times do
+ title = Faker::Lorem.sentence(3)
+ description = Faker::Lorem.sentence(7)
+ users.each { |user| user.gramposts.create!(title: title, description: description) }
+ 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
Oops, something went wrong.

0 comments on commit 9925ddd

Please sign in to comment.