gitlab-org--gitlab-foss/app/controllers/projects/milestones_controller.rb
Yorick Peterse 4ff75e3179 Improve performance of sorting milestone issues
This cuts down the time it takes to sort issues of a milestone by about
10x. In the previous setup the code would run a SQL query for every
issue that had to be sorted. The new setup instead runs a single SQL
query to update all the given issues at once.

The attached benchmark used to run at around 60 iterations per second,
using the new setup this hovers around 600 iterations per second. Timing
wise a request to update a milestone with 40-something issues would take
about 760 ms, in the new setup this only takes about 130 ms.

Fixes #3066
2015-10-19 11:37:14 +02:00

112 lines
3 KiB
Ruby

class Projects::MilestonesController < Projects::ApplicationController
before_action :module_enabled
before_action :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests]
# Allow read any milestone
before_action :authorize_read_milestone!
# Allow admin milestone
before_action :authorize_admin_milestone!, except: [:index, :show]
respond_to :html
def index
@milestones = case params[:state]
when 'all'; @project.milestones.order("state, due_date DESC")
when 'closed'; @project.milestones.closed.order("due_date DESC")
else @project.milestones.active.order("due_date ASC")
end
@milestones = @milestones.includes(:project)
@milestones = @milestones.page(params[:page]).per(PER_PAGE)
end
def new
@milestone = @project.milestones.new
respond_with(@milestone)
end
def edit
respond_with(@milestone)
end
def show
@issues = @milestone.issues
@users = @milestone.participants.uniq
@merge_requests = @milestone.merge_requests
end
def create
@milestone = Milestones::CreateService.new(project, current_user, milestone_params).execute
if @milestone.save
redirect_to namespace_project_milestone_path(@project.namespace,
@project, @milestone)
else
render "new"
end
end
def update
@milestone = Milestones::UpdateService.new(project, current_user, milestone_params).execute(milestone)
respond_to do |format|
format.js
format.html do
if @milestone.valid?
redirect_to namespace_project_milestone_path(@project.namespace,
@project, @milestone)
else
render :edit
end
end
end
end
def destroy
return access_denied! unless can?(current_user, :admin_milestone, @project)
Milestones::DestroyService.new(project, current_user).execute(milestone)
respond_to do |format|
format.html { redirect_to namespace_project_milestones_path }
format.js { render nothing: true }
end
end
def sort_issues
@milestone.sort_issues(params['sortable_issue'].map(&:to_i))
render json: { saved: true }
end
def sort_merge_requests
@merge_requests = @milestone.merge_requests.where(id: params['sortable_merge_request'])
@merge_requests.each do |merge_request|
merge_request.position = params['sortable_merge_request'].index(merge_request.id.to_s) + 1
merge_request.save
end
render json: { saved: true }
end
protected
def milestone
@milestone ||= @project.milestones.find_by!(iid: params[:id])
end
def authorize_admin_milestone!
return render_404 unless can?(current_user, :admin_milestone, @project)
end
def module_enabled
unless @project.issues_enabled || @project.merge_requests_enabled
return render_404
end
end
def milestone_params
params.require(:milestone).permit(:title, :description, :due_date, :state_event)
end
end