Skip to content
This repository has been archived by the owner on Dec 8, 2021. It is now read-only.

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
torresed committed Feb 22, 2021
1 parent 2c367b7 commit 0be5fcc
Show file tree
Hide file tree
Showing 13 changed files with 102 additions and 100 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class FriendshipsController < ApplicationController
class FriendsController < ApplicationController
before_action :check_token, :users
skip_before_action :users, only: %i[show]

Expand All @@ -9,7 +9,7 @@ def show
end

def create
@friendship = Friendship.request(@user, @friend)
@friendship = Friends.request(current_user, @friend)
if @friendship.nil?
render status: :bad_request, json: { error: 'Friend request could not be sent.' }
else
Expand All @@ -18,17 +18,17 @@ def create
end

def update
@friendship = Friendship.find_by(sent_by: @friend, sent_to: current_user, status: 'pending')
@friendship = Friends.find_by(sent_by: @friend, sent_to: current_user, status: :pending)
if @friendship.nil?
render status: :bad_request, json: { error: 'Friend request could not be accepted.' }
else
@friendship.accepted!
@friendship.confirmed!
render status: :ok, json: { success: 'Friend request has been accepted.' }
end
end

def destroy
@friendship = Friendship.find_by(sent_by: @friend, sent_to: current_user).presence || Friendship.find_by(sent_by: current_user, sent_to: @friend).presence
@friendship = Friends.find_by(sent_by: @friend, sent_to: current_user).presence || Friends.find_by(sent_by: current_user, sent_to: @friend).presence
if @friendship.nil?
render status: :bad_request, json: { error: 'Friend could not be removed.' }
else
Expand Down
16 changes: 16 additions & 0 deletions app/models/friends.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class Friends < ApplicationRecord
belongs_to :sent_to, class_name: 'User'
belongs_to :sent_by, class_name: 'User'

enum status: { pending: 0, confirmed: 1 }
scope :pending, -> { where(status: :pending) }
scope :confirmed, -> { where(status: :confirmed) }

def self.request(user, friend)
return if (user == friend) || find_by(sent_by: user, sent_to: friend).present?

user.requests_sent.create(sent_to: friend, status: :pending)
end
end
21 changes: 0 additions & 21 deletions app/models/friendship.rb

This file was deleted.

19 changes: 11 additions & 8 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ class User < ApplicationRecord
has_secure_token :password_recovery_token
after_commit :send_confirmation_email, only: %i[create update], if: -> { saved_change_to_unconfirmed_email? && !unconfirmed_email.nil? }

has_many :friendships_sent, class_name: 'Friendship', foreign_key: 'sent_by_id', inverse_of: 'sent_by', dependent: :destroy
has_many :friendships_received, class_name: 'Friendship', foreign_key: 'sent_to_id', inverse_of: 'sent_to', dependent: :destroy
has_many :connections, -> { merge(Friendship.accepted) }, through: :friendships_sent, source: :sent_to
has_many :inverse_connections, -> { merge(Friendship.accepted) }, through: :friendships_received, source: :sent_by
has_many :pending_requests, -> { merge(Friendship.pending) }, through: :friendships_sent, source: :sent_to
has_many :received_requests, -> { merge(Friendship.pending) }, through: :friendships_received, source: :sent_by

validates :email, length: 1..100, format: { with: URI::MailTo::EMAIL_REGEXP }, allow_nil: true
validates :unconfirmed_email, exclusion: { in: ->(u) { [u.email] } }, length: 1..100, format: { with: URI::MailTo::EMAIL_REGEXP }, allow_nil: true
validates :username, presence: true, uniqueness: true, length: 3..100
Expand All @@ -22,8 +15,18 @@ class User < ApplicationRecord
validates :email_confirmation_token, uniqueness: true, allow_nil: true
validates :password_recovery_token, uniqueness: true, allow_nil: true

# Request associations.
has_many :requests_sent, class_name: 'Friends', foreign_key: 'sent_by_id', inverse_of: 'sent_by', dependent: :destroy
has_many :requests_received, class_name: 'Friends', foreign_key: 'sent_to_id', inverse_of: 'sent_to', dependent: :destroy

# Friendship associations.
has_many :friended, -> { merge(Friends.confirmed) }, through: :requests_sent, source: :sent_to
has_many :friended_by, -> { merge(Friends.confirmed) }, through: :requests_received, source: :sent_by
has_many :friends_pending, -> { merge(Friends.pending) }, through: :requests_sent, source: :sent_to
has_many :friends_awaiting, -> { merge(Friends.pending) }, through: :requests_received, source: :sent_by

def friends
connections + inverse_connections
friended + friended_by
end

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ json.friends do
json.array! @user.friends, :username
end

json.pending_requests do
json.array! @user.pending_requests, :username
json.friends_pending do
json.array! @user.friends_pending, :username
end

json.received_requests do
json.array! @user.received_requests, :username
json.friends_awaiting do
json.array! @user.friends_awaiting, :username
end
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

Rails.application.routes.draw do
resource :user, only: %i[create update show]

post :session, to: 'users#create_session'
delete :session, to: 'users#destroy_session'

get '/confirm/:email_confirmation_token', to: 'users#confirm_email', as: 'confirm_email'
post '/password/recovery', to: 'users#password_recovery'
get '/password/reset/:password_recovery_token', to: 'users#password_reset', as: 'password_reset'
post '/password/reset/:password_recovery_token', to: 'users#password_update', as: 'password_update'

resource :friends, only: %i[show create update destroy]
end
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# frozen_string_literal: true

class CreateFriendships < ActiveRecord::Migration[6.1]
class CreateFriends < ActiveRecord::Migration[6.1]
def change
create_table :friendships, id: false do |t|
create_table :friends, id: false do |t|
t.ksuid_binary :id, primary_key: true

t.references :sent_by, foreign_key: { to_table: :users }, type: 'blob(20)'
Expand Down
10 changes: 5 additions & 5 deletions db/schema.rb

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

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

FactoryBot.define do
factory :friendship, class: 'Friendship' do
factory :friends, class: 'Friends' do
sent_by factory: :user
association :sent_to, factory: :user
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

require 'rails_helper'

RSpec.describe Friendship, type: :model do
RSpec.describe Friends, type: :model do
let(:requester) { create(:user) }
let(:requestee) { create(:user) }
let(:friendship) { create(:friendship, sent_by_id: requester.id, sent_to_id: requestee.id) }
let(:friendship) { create(:friends, sent_by_id: requester.id, sent_to_id: requestee.id) }

it 'is valid with valid attributes' do
expect(friendship).to be_valid
Expand All @@ -22,7 +22,7 @@
end

it 'is valid with correct status' do
friendship.status = 'accepted'
friendship.status = 'confirmed'
expect(friendship).to be_valid
end

Expand All @@ -32,6 +32,6 @@

it 'sends a friend request' do
described_class.request(requester, requestee)
expect(requester.pending_requests).to include(requestee)
expect(requester.friends_pending).to include(requestee)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,41 @@

require 'rails_helper'

RSpec.describe FriendshipsController, type: :request do
RSpec.describe FriendsController, type: :request do
context 'when logged out' do
let(:friend) { create(:user) }

describe 'GET #show' do
it 'renders an unauthorized response' do
get friendship_url, as: :json
get friends_url, as: :json
expect(response).to have_http_status(:unauthorized)
end
end

describe 'POST #create' do
it 'renders an unauthorized response' do
post friendship_url, as: :json
post friends_url, as: :json
expect(response).to have_http_status(:unauthorized)
end
end

describe 'PATCH #update' do
it 'renders an unauthorized response' do
patch friendship_url, params: { id: friend.id.to_s }, as: :json
patch friends_url, params: { id: friend.id.to_s }, as: :json
expect(response).to have_http_status(:unauthorized)
end
end

describe 'PUT #update' do
it 'renders an unauthorized response' do
put friendship_url, params: { id: friend.id.to_s }, as: :json
put friends_url, params: { id: friend.id.to_s }, as: :json
expect(response).to have_http_status(:unauthorized)
end
end

describe 'DELETE #destroy' do
it 'renders an unauthorized response' do
delete friendship_url, params: { id: friend.id.to_s }, as: :json
delete friends_url, params: { id: friend.id.to_s }, as: :json
expect(response).to have_http_status(:unauthorized)
end
end
Expand All @@ -56,63 +56,63 @@

describe 'GET #show' do
it 'gets friend list' do
get friendship_url, headers: valid_headers, as: :json
get friends_url, headers: valid_headers, as: :json
expect(response).to have_http_status(:ok)
end
end

describe 'POST #create' do
it 'sends a friend request' do
post friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
post friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend request has been sent.'))
expect(user.pending_requests).to include(friend)
expect(user.friends_pending).to include(friend)
end
end

it 'fails to send a self request' do
post friendship_url, params: { id: user.id.to_s }, headers: valid_headers, as: :json
post friends_url, params: { id: user.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend request could not be sent.'))
expect(user.friends).not_to include(user)
end

it 'fails to send friend request if there is one already pending' do
Friendship.request(user, friend)
post friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
Friends.request(user, friend)
post friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend request could not be sent.'))
end

describe 'PUT #update' do
it 'accepts a friend request' do
Friendship.request(friend, user)
put friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
Friends.request(friend, user)
put friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend request has been accepted.'))
expect(friend.friends).to include(user)
end

it 'fails to accept a nonexistent friend request ' do
put friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
put friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend request could not be accepted.'))
expect(user.friends).not_to include(friend)
expect(friend.friends).not_to include(user)
end
end

describe 'DELETE #destroy' do
it 'removes a friendship request' do
Friendship.request(user, friend)
delete friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
it 'removes a friends request' do
Friends.request(user, friend)
delete friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend has been removed.'))
expect(user.pending_requests).not_to include(friend)
expect(user.friends_pending).not_to include(friend)
end

it 'removes a friendship' do
Friendship.create(sent_by: user, sent_to: friend, status: 'accepted')
delete friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
it 'removes a friends' do
Friends.create(sent_by: user, sent_to: friend, status: 'confirmed')
delete friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(user.friends).not_to include(friend)
end

it 'fails to remove a nonexistent friend' do
delete friendship_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
delete friends_url, params: { id: friend.id.to_s }, headers: valid_headers, as: :json
expect(response.body).to match(a_string_including('Friend could not be removed.'))
end
end
Expand Down
27 changes: 27 additions & 0 deletions spec/routing/friends_routing_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe FriendsController, type: :routing do
describe 'routing' do
it 'routes to #show via GET' do
expect(get: '/friends').to route_to('friends#show')
end

it 'routes to #create via POST' do
expect(post: '/friends').to route_to('friends#create')
end

it 'routes to #update via PUT' do
expect(put: '/friends').to route_to('friends#update')
end

it 'routes to #update via PATCH' do
expect(patch: '/friends').to route_to('friends#update')
end

it 'routes to #destroy via DELETE' do
expect(delete: '/friends').to route_to('friends#destroy')
end
end
end
Loading

0 comments on commit 0be5fcc

Please sign in to comment.