Skip to content

Commit

Permalink
Gate perf optimization (#167)
Browse files Browse the repository at this point in the history
* remove N+1 queries when fetching group expiration date

* update code that use user.group_expiration_date

* update spec to prevent race condition

* add apt-key for travis

* fix apt-key to be received

* use xenial instead of trusty because mysql package in trusty won't be generated anymore

* remove unnecessary step
  • Loading branch information
giosakti authored Aug 6, 2019
1 parent 22ee633 commit 525ddd7
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 36 deletions.
8 changes: 1 addition & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
dist: xenial
sudo: required
language: ruby
rvm:
- ruby-2.4.4
services:
- redis-server
- mysql
addons:
apt:
sources:
- mysql-5.7-trusty
packages:
- mysql-server
- mysql-client

env:
global:
Expand Down
15 changes: 10 additions & 5 deletions app/controllers/groups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,16 @@ def new
end

def show
# This is set in before_action filter
# @group = Group.find(params[:id])
@vpns = Vpn.all.select { |vpn| vpn.groups.count.zero? }
@users = User.where(active: true)
@host_machines = HostMachine.all
@group_users = User.
select(%Q{
users.id AS id,
name,
email,
active,
group_associations.expiration_date AS group_expiration_date
}).
joins('LEFT OUTER JOIN group_associations ON users.id = group_associations.user_id').
where('group_associations.group_id = ?', @group.id)
end

def delete_machine
Expand Down
11 changes: 10 additions & 1 deletion app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ def index

def show
@user = User.where(id: params[:id]).first
@user_groups = Group.
select(%{
groups.id AS id,
gid,
name,
deleted_at,
group_associations.expiration_date AS group_expiration_date
}).
joins('INNER JOIN group_associations ON groups.id = group_associations.group_id').
where('group_associations.user_id = ?', @user.id)

if @user.access_token.blank?
access_token = AccessToken.new
Expand All @@ -23,7 +33,6 @@ def show

return unless current_user.admin? || current_user == @user

@groups = Group.all
render_404 if @user.blank?

return unless @user.present? && (current_user.admin? || current_user.id == @user.id)
Expand Down
4 changes: 0 additions & 4 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,6 @@ def group_admin?
GroupAdmin.find_by_user_id(self.id).present?
end

def group_expiration_date(group_id)
group_associations.detect { |assoc| assoc.group_id == group_id }.expiration_date
end

private

def remove_default_admin
Expand Down
8 changes: 4 additions & 4 deletions app/views/groups/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
br
.card
.card-body
h6.card-title Groups Members (#{@group.users.count})
h6.card-title Groups Members (#{@group_users.length})
.table-responsive
table.table.table-striped
thead
Expand All @@ -46,7 +46,7 @@
th Expiration Date
th
tbody
- @group.users.sort_by{ |user| user.email}.each do |user|
- @group_users.sort_by{ |user| user.email}.each do |user|
tr
td
- if user.active?
Expand All @@ -56,12 +56,12 @@
td
= "#{user.email}"
td
= "#{user.group_expiration_date @group.id}"
= "#{user.group_expiration_date}"
td
= link_to "Delete", [@group, user], method: :delete, data: {confirm: 'Are you sure to remove this user from the group?'} if current_user.admin or @group.admin?(current_user)

br
= "*This group does not have any group members" if @group.users.count == 0
= "*This group does not have any group members" if @group_users.length == 0
br
- if current_user.admin or @group.admin?(current_user)
.h7 Assign members
Expand Down
4 changes: 2 additions & 2 deletions app/views/users/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@
th Expiration Date
th Action
tbody
- @user.groups.each do |group|
- @user_groups.each do |group|
- unless group.deleted?
tr
td
= "#{group.name} (#{group.gid})"
td
= "#{@user.group_expiration_date group.id}"
= "#{group.group_expiration_date}"
td
= link_to "Remove group", [@user, group], method: :delete, data: {confirm: 'Are you sure to delete this group?'} if current_user.admin?
br
Expand Down
38 changes: 38 additions & 0 deletions spec/controllers/groups_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,44 @@
end
end

describe 'GET #show' do
context 'unauthenticated' do
it 'should return 302' do
get :index

expect(response).to have_http_status(302)
end
end

context 'authenticated as admin' do
context '' do
it 'should return specified group' do
sign_in admin
group = create(:group)
get :show, params: { id: group.id }
expect(response).to have_http_status(200)
end

it 'should populate group_users instance variable' do
sign_in admin
user = create(:user)
group = create(:group)
create(:group_association, group_id: group.id, user_id: user.id, expiration_date: '2020-01-01')
get :show, params: { id: group.id }
expect(assigns(:group_users).first.to_json).to eq(
{
id: user.id,
email: user.email,
name: user.name,
active: user.active,
group_expiration_date: '2020-01-01'
}.to_json
)
end
end
end
end

describe 'POST #add_user' do
context 'unauthenticated' do
it 'should return 302' do
Expand Down
34 changes: 34 additions & 0 deletions spec/controllers/users_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,40 @@
let!(:group) { FactoryBot.create(:group) }
let(:user) { FactoryBot.create(:user, name: "foobar", user_login_id: "foobar", email: "[email protected]") }

describe 'GET #show' do
context 'unauthenticated' do
it 'should return 302' do
get :index

expect(response).to have_http_status(302)
end
end

context 'authenticated' do
it 'should return specified user' do
sign_in user
get :show, params: { id: user.id }
expect(response).to have_http_status(200)
end

it 'should populate user_groups instance variable' do
sign_in user
create(:group_association, group_id: group.id, user_id: user.id, expiration_date: '2020-01-01')
get :show, params: { id: user.id }
expected_group = assigns(:user_groups).select { |user_group| user_group.id == group.id }
expect(expected_group.first.to_json).to eq(
{
id: group.id,
name: group.name,
gid: group.gid,
deleted_at: group.deleted_at,
group_expiration_date: '2020-01-01',
}.to_json
)
end
end
end

context "update user profile" do
it "should update profile with product name" do
sign_in user
Expand Down
13 changes: 0 additions & 13 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -311,19 +311,6 @@
end
end

describe '#group_expiration_date' do
it 'should return expiration date from group' do
user = create(:user)
group = create(:group)
expiration_date = Date.parse('2019-10-20')
group.add_user_with_expiration(user.id, expiration_date)

user_expiration_date = user.group_expiration_date group.id

expect(user_expiration_date).to eq(expiration_date)
end
end

describe '#uid' do
it 'should check uid creation with offset' do
user = create(:user)
Expand Down
1 change: 1 addition & 0 deletions spec/views/groups/show.html.slim_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
it 'should renders form to add user to group' do
sign_in admin
assign(:group, group)
assign(:group_users, [])

render

Expand Down

0 comments on commit 525ddd7

Please sign in to comment.