Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelSipayung committed Jan 17, 2024
2 parents 7bd6f5a + 582b275 commit eb420a5
Show file tree
Hide file tree
Showing 19 changed files with 381 additions and 142 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/rubyonrails.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# This workflow uses actions that are not certified by GitHub. They are
# provided by a third-party and are governed by separate terms of service,
# privacy policy, and support documentation.
#
# This workflow will install a prebuilt Ruby version, install dependencies, and
# run tests and linters.
name: "Ruby on Rails CI"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:11-alpine
ports:
- "5432:5432"
env:
POSTGRES_DB: rails_test
POSTGRES_USER: rails
POSTGRES_PASSWORD: password
env:
RAILS_ENV: test
DATABASE_URL: "postgres://rails:password@localhost:5432/rails_test"
steps:
- name: Checkout code
uses: actions/checkout@v3
# Add or replace dependency steps here
- name: Install Ruby and gems
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
with:
bundler-cache: true
# Add or replace database setup steps here
- name: Set up database schema
run: bin/rails db:schema:load
# Add or replace test runners here
- name: Run tests
run: bin/rake

lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Ruby and gems
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
with:
bundler-cache: true
# Add or replace any other lints here
- name: Security audit dependencies
run: bin/bundler-audit --update
- name: Security audit application code
run: bin/brakeman -q -w2
- name: Lint Ruby files
run: bin/rubocop --parallel
8 changes: 4 additions & 4 deletions .idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

262 changes: 134 additions & 128 deletions .idea/sample_app.iml

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class UsersController < ApplicationController
#prevent use update data or delete without login first
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
#show all users
Expand Down Expand Up @@ -52,7 +52,18 @@ def update #update the user
render 'edit'
end
end

def following #show the following user
@title = "Following"
@user = User.find(params[:id])
@users = @user.following.paginate(page: params[:page]) #using pagination style
render "show_follow"
end
def followers #show the followers user
@title = "Followers"
@user = User.find(params[:id])
@users = @user.followers.paginate(page: params[:page]) #using pagination style
render "show_follow"
end
private
#only allow the user to edit their own data
def correct_user
Expand Down
5 changes: 5 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ class User < ApplicationRecord
foreign_key: 'follower_id', dependent: :destroy
#using source to tell rails to look for followed_id in active_relationships table
has_many :following, through: :active_relationships, source: :followed
#follower: user.follower to go with user.following
has_many :passive_relationships, class_name: 'Relationship',
foreign_key: 'followed_id', dependent: :destroy
#using source to tell rails to look for follower_id in passive_relationships table
has_many :followers, through: :passive_relationships, source: :follower
#add destroy: since destroying a user should also destroy that user relationship, add dependent
#example: @user.microposts.build(content: "lorem ipsum")
#create accessible attribute for remember_token
Expand Down
17 changes: 17 additions & 0 deletions app/views/shared/_stats.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!--since we will including stats both user show pages and home page -->
<!-- nothing happen if @user is nil -->
<% @user ||= current_user %>
<div class="stats">
<a href="<%= following_user_path(@user) %>">
<strong id="following" class="start">
<%= @user.following.count %>
</strong>
following
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id="followers" class="start">
<%= @user.followers.count %>
</strong>
followers
</a>
</div>
3 changes: 3 additions & 0 deletions app/views/static_pages/home.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="stats">
<%= render 'shared/stats' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
Expand Down
7 changes: 7 additions & 0 deletions app/views/users/_follow.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= form_with(model: current_user.active_relationships.build, local: true) do |f| %>
<div>
<!-- using hidden field to pass the followed_id to the create action -->
<%= hidden_field_tag :followed_id, @user.id %>
</div>
<%= f.submit "Follow", class: "btn btn-primary"%>
<%end %>
9 changes: 9 additions & 0 deletions app/views/users/_follow_form.html.erb
Original file line number Diff line number Diff line change
@@ -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 %>
4 changes: 4 additions & 0 deletions app/views/users/_unfollow.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%=form_with(model: current_user.active_relationships.find_by(followed_id: @user.id),
html: {method: :delete}, local: true) do |f| %>
<%= f.submit "Unfollow", class: "btn"%>
<%end %>
20 changes: 16 additions & 4 deletions app/views/users/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
<h1 class="text-center">
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
<div class="row">
<aside class="col-md-4">
<section>
<h1 class="text-center">
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>

<section class="stats">
<%= render 'shared/stats' %>
</section>
</aside>
</div>

<div class="col-md-8">
<%= render 'follow_form' if logged_in? %>
<% if @user.microposts.any? %>
<h3> Micropost (<%= @user.microposts.count %>)</h3>
<ol class="micropost">
Expand Down
30 changes: 30 additions & 0 deletions app/views/users/show_follow.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<% 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>Micropost: </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), user %>
<%end %>
</div>
<%end %>
</section>
</aside>
<div class="col-md-8">
<h3><%= @title %></h3>
<%if @users.any? %>
<ul class="users follow">
<% render @users %>
</ul>
<%= will_paginate %>
<%end %>
</div>
</div>
14 changes: 11 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
post 'login', to: 'sessions#create' #create the session
#delete the session
delete '/logout', to: 'sessions#destroy' #delete the session
resources :users do #add following and followers action
member do #member: get the user id
get :following, :followers #get the following and followers,
# url: /users/1/following and /users/1/followers,
# named following_user_path(1) and followers_user_path(1)
end
end
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
Expand All @@ -27,7 +34,8 @@
#root "application#hello"
# Defines the root path route ("/")
# root "posts#index"
resources :account_activations, only: [:edit]
resources :password_resets, only: [:edit, :new, :update, :create]
resources :microposts, only: [:create, :destroy]
resources :account_activations, only: [:edit]
resources :password_resets, only: [:edit, :new, :update, :create]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
end
7 changes: 7 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@
#each user will contain 50 posts
users.each {|user| user.microposts.create!(content: content)}
end
#generate following relationship
users = User.all
user = users.first
following = users[2..50] #follow users 2 to 50
followers = users[3..49] #followers users 3 to 49
following.each { |followed| user.follow(followed)} #follow each user
followers.each {|follower| follower.follow(user)} #each user follow user
8 changes: 8 additions & 0 deletions test/controllers/users_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,13 @@ def setup
end
assert_redirected_to users_url
end
test "should redirect following when not logged in" do
get following_user_path(@user)
assert_redirected_to login_url
end
test "should redirect followers when not logged in" do
get followers_user_path(@user)
assert_redirected_to login_url
end

end
18 changes: 17 additions & 1 deletion test/fixtures/relationships.yml
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
follower: michael
followed: iana

two:
follower: michael
followed: malory

three:
follower: iana
followed: michael

four:
follower: archer
followed: michael

12 changes: 12 additions & 0 deletions test/fixtures/users.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ archer: #for invalid access
password_digest: <%=User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
iana: #for invalid access
name: iana sigh
email: [email protected]
password_digest: <%=User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
malory:
name: Malory Archer
email: [email protected]
password_digest: <%=User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
one:
name: MyString
email: user_one_<%= Time.now.to_f %>@example.com
Expand Down
25 changes: 25 additions & 0 deletions test/integration/following_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require "test_helper"

class FollowingTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
get login_path
post login_path, params: {session: {email: @user.email, password: 'password'}}
end
test "following page" do
get following_user_path(@user)
assert_not @user.following.empty?
assert_match @user.following.count.to_s, response.body
@user.following.each do |user|
assert_select 'a[href=?]', user_path(user) #check if the link is correct
end
end
test "followers page" do
get followers_user_path(@user)
assert_not @user.followers.empty?
assert_match @user.followers.count.to_s, response.body #check if the link is correct
@user.followers.each do |user|
assert_select 'a[href=?]', user_path(user)
end
end
end
1 change: 1 addition & 0 deletions test/models/user_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def setup
assert_not michael.following?(archer)
michael.follow(archer)
assert michael.following?(archer)
assert archer.followers.include?(michael)
michael.unfollow(archer)
assert_not michael.following?(archer)
end
Expand Down

0 comments on commit eb420a5

Please sign in to comment.