Skip to content

Commit

Permalink
Add user following
Browse files Browse the repository at this point in the history
  • Loading branch information
richardjortega committed Jul 2, 2012
1 parent 8f6f528 commit 42433f1
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 51 deletions.
21 changes: 21 additions & 0 deletions app/controllers/relationships_controller.rb
@@ -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
7 changes: 7 additions & 0 deletions app/models/micropost.rb
Expand Up @@ -8,4 +8,11 @@ class Micropost < ActiveRecord::Base

# order reverse chronologically with microposts
default_scope order: 'microposts.created_at DESC'

# 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
4 changes: 3 additions & 1 deletion app/models/user.rb
Expand Up @@ -35,7 +35,9 @@ class User < ActiveRecord::Base

def feed
# This is preliminary. See "Following users" for the full implementation.
Micropost.where("user_id = ?", id)
#Micropost.where("user_id = ?", id)
# Full implementation
Micropost.from_users_followed_by(self)
end

def following?(other_user)
Expand Down
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 %>')
2 changes: 1 addition & 1 deletion app/views/users/_follow.html.erb
@@ -1,4 +1,4 @@
<%= form_for(current_user.relationships.build(followed_id: @user.id)) do |f| %>
<%= 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 %>
2 changes: 1 addition & 1 deletion app/views/users/_unfollow.html.erb
@@ -1,3 +1,3 @@
<%= form_for(current_user.relationships.find_by_followed_id(@user), html: { method: :delete}) do |f| %>
<%= 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 %>
41 changes: 41 additions & 0 deletions spec/controllers/relationships_controller_spec.rb
@@ -0,0 +1,41 @@
require 'spec_helper'

describe RelationshipsController do

let(:user) { FactoryGirl.create(:user) }
let(:other_user) { FactoryGirl.create(:user) }

before { sign_in user }

describe "creating a relationship with Ajax" do

it "should increment the Relationship count" do
expect do
xhr :post, :create, relationship: { followed_id: other_user.id }
end.should change(Relationship, :count).by(1)
end

it "should respond with success" do
xhr :post, :create, relationship: { followed_id: other_user.id }
response.should be_success
end
end

describe "destroying a relationship with Ajax" do

before { user.follow!(other_user) }
let(:relationship) { user.relationships.find_by_followed_id(other_user) }

it "should decrement the Relationship count" do
expect do
xhr :delete, :destroy, id: relationship.id
end.should change(Relationship, :count).by(-1)
end

it "should respond with success" do
xhr :delete, :destroy, id: relationship.id
response.should be_success
end
end

end
11 changes: 11 additions & 0 deletions spec/models/user_spec.rb
Expand Up @@ -152,10 +152,21 @@
let(:unfollowed_post) do
FactoryGirl.create(:micropost, user: FactoryGirl.create(:user))
end
let(:followed_user) { FactoryGirl.create(:user) }

before do
@user.follow!(followed_user)
3.times { followed_user.microposts.create!(content: "Lorem ipsum") }
end

its(:feed) { should include(newer_micropost) }
its(:feed) { should include(older_micropost) }
its(:feed) { should_not include(unfollowed_post) }
its(:feed) do
followed_user.microposts.each do |micropost|
should include(micropost)
end
end
end
end

Expand Down
119 changes: 71 additions & 48 deletions spec/requests/authentication_pages_spec.rb
@@ -1,55 +1,56 @@
require 'spec_helper'

describe "Authentication" do

subject { page }

describe "signin page" do
before { visit signin_path }
before { visit signin_path }

it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
end

describe "signin" do
before { visit signin_path }
before { visit signin_path }

describe "with invalid information" do
before { click_button "Sign in" }
describe "with invalid information" do
before { click_button "Sign in" }

it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }

describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end

describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end

describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
it { should have_selector('title', text: user.name) }

it { should have_selector('title', text: user.name) }

it { should have_link('Users', href: users_path)}
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }

it { should_not have_link('Sign in', href: signin_path) }
it { should have_link('Users', href: users_path) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }

describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
end
end

describe "authorization" do



describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }

Expand All @@ -66,23 +67,23 @@
it "should render the desired protected page" do
page.should have_selector('title', text: 'Edit user')
end
end

describe "in the Microposts controller" do

describe "submitting to the create action" do
before { post microposts_path }
specify { response.should redirect_to(signin_path) }
end

describe "submitting to the destroy action" do
before { delete micropost_path(FactoryGirl.create(:micropost)) }
specify { response.should redirect_to(signin_path)}
describe "when signing in again" do
before do
delete signout_path
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end

it "should render the default (profile) page" do
page.should have_selector('title', text: user.name)
end
end
end
end

end

describe "in the Users controller" do

describe "visiting the edit page" do
Expand All @@ -95,7 +96,7 @@
specify { response.should redirect_to(signin_path) }
end

describe "visiting the user index" do
describe "visiting user index" do
before { visit users_path }
it { should have_selector('title', text: 'Sign in') }
end
Expand All @@ -109,7 +110,31 @@
before { visit followers_user_path(user) }
it { should have_selector('title', text: 'Sign in') }
end
end

describe "in the Microposts controller" do

describe "submitting to the create action" do
before { post microposts_path }
specify { response.should redirect_to(signin_path) }
end

describe "submitting to the destroy action" do
before { delete micropost_path(FactoryGirl.create(:micropost)) }
specify { response.should redirect_to(signin_path) }
end
end

describe "in the Relationships controller" do
describe "submitting to the create action" do
before { post relationships_path }
specify { response.should redirect_to(signin_path) }
end

describe "submitting to the destroy action" do
before { delete relationship_path(1) }
specify { response.should redirect_to(signin_path) }
end
end
end

Expand All @@ -120,7 +145,7 @@

describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
it { should have_selector('title', text: full_title('')) }
end

describe "submitting a PUT request to the Users#update action" do
Expand All @@ -135,12 +160,10 @@

before { sign_in non_admin }

describe "submitting a DELETE request to the Users#Destroy action" do
describe "submitting a DELETE request to the Users#destroy action" do
before { delete user_path(user) }
specify { response.should redirect_to(root_path) }
specify { response.should redirect_to(root_path) }
end
end

end

end
end

0 comments on commit 42433f1

Please sign in to comment.