Permalink
Browse files

First pass at better performance for the site in general. Try loading…

… data after the page has loaded JS/CSS. Also, I shrunk the size of the payload by ~66% while preserving all of the data transferred.

Squashed commit of the following:

commit 3e980f34143226b6c06e85bed1c3ad66b7b41160
Author: Rob Sterner <rob.sterner@gmail.com>
Date:   Sun Dec 1 21:39:13 2013 -0500

    First pass at improving application performance. Load the data *after* initially rendering the site.

commit 1805d3405e3df125ddcd3a7ca7f2b353109de1e4
Author: Rob Sterner <rob.sterner@gmail.com>
Date:   Sun Dec 1 21:37:24 2013 -0500

    Bump version of lodash, add string.js and async.js.

commit ac1b94430009782c5f45e278752bb524bef182bf
Author: Rob Sterner <rob.sterner@gmail.com>
Date:   Sun Dec 1 21:35:58 2013 -0500

    Try using unicorn in production. Might help with page load times by handling multiple concurrent requests.

commit d97b4d0d8fc6426d93e29349d35cac5b4e577e71
Author: Rob Sterner <rob.sterner@gmail.com>
Date:   Sun Dec 1 21:34:44 2013 -0500

    New .powconfig, start pow with 3 worker processes.
  • Loading branch information...
1 parent aaeb328 commit b74061db1a9d52ad08b0f0181df021107d5dd1f5 @fermion fermion committed Dec 2, 2013
View
@@ -0,0 +1 @@
+export POW_WORKERS=3
View
@@ -57,5 +57,6 @@ end
group :production do
gem 'memcache-client'
+ gem 'unicorn'
end
View
@@ -96,6 +96,7 @@ GEM
blankslate (>= 2.1.2.4)
journey (1.0.4)
json (1.8.1)
+ kgio (2.8.1)
launchy (2.1.2)
addressable (~> 2.3)
mail (2.5.4)
@@ -157,6 +158,7 @@ GEM
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
+ raindrops (0.12.0)
rake (10.1.0)
rdoc (3.12.2)
json (~> 1.4)
@@ -207,6 +209,10 @@ GEM
uglifier (1.2.7)
execjs (>= 0.3.0)
multi_json (~> 1.3)
+ unicorn (4.7.0)
+ kgio (~> 2.6)
+ rack
+ raindrops (~> 0.7)
will_paginate (3.0.3)
PLATFORMS
@@ -250,4 +256,5 @@ DEPENDENCIES
taps
thin
uglifier (>= 1.0)
+ unicorn
will_paginate
View
@@ -1 +1 @@
-web: bundle exec rails server thin -p $PORT
+web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
@@ -9,6 +9,8 @@
//= require moment
//= require d3.v2
//= require bootstrap
+//= require async
+//= require string
//= require lodash
//= require backbone
@@ -94,15 +94,15 @@ class StaffPlan.Routers.StaffPlan extends Support.SwappingRouter
router: @
clients: window.StaffPlan.clients
collection: window.StaffPlan.projects
- currentUser: window.StaffPlan.users.get(@currentUser.id)
+ currentUser: window.StaffPlan.users.get(@currentUser.get("id"))
@swap projectNew
projectEdit: (projectId) ->
project = window.StaffPlan.projects.get projectId
projectEdit = new window.StaffPlan.Views.Projects.Edit
router: @
clients: window.StaffPlan.clients
- currentUser: window.StaffPlan.users.get(@currentUser.id)
+ currentUser: window.StaffPlan.users.get(@currentUser.get('id'))
model: project
collection: window.StaffPlan.projects
@swap projectEdit
@@ -18,47 +18,102 @@ window.StaffPlan =
Clients: {}
Routers: {}
Dispatcher: _.extend {}, Backbone.Events
-
+
+ loadData: (type, callback) ->
+ $.ajax "/#{type}.json",
+ success: (json) =>
+ console.log("loaded #{type}")
+ @[type] = new StaffPlan.Collections[S(type).capitalize().toString()] json
+ @addProgress()
+ callback(null, type);
+
+ error: =>
+ console.log("failed to load #{type}")
+ callback("failed to load data for #{type}")
+
+ loadAssignments: (callback) ->
+ $.ajax "/assignments.json",
+ success: (json) =>
+ console.log("loaded assignments")
+
+ _.forEach json, (assignment) ->
+ work_weeks = assignment.work_weeks
+ delete assignment.work_weeks
+ assignment.work_weeks = _.map work_weeks, (work_week) -> _.object(['id', 'actual_hours', 'estimated_hours', 'beginning_of_week', 'proposed'], work_week)
+
+ # work_weeks are sent as an array of arrays with a specific ordering to cut down on bytes sent over the wire.
+ @assignments = new StaffPlan.Collections.Assignments json
+
+ @addProgress()
+
+ # @[type] = new StaffPlan.Collections[S(type).capitalize().toString()] json
+ callback(null, "assignments");
+
+ error: =>
+ console.log("failed to load assignments")
+ callback("failed to load data for assignments")
+
+ addProgress: ->
+ barElement = $('.progress .bar')
+
+ if barElement.attr('style') == undefined
+ newWidth = "20%"
+ else
+ newWidth = parseInt(barElement.attr("style").replace(/[\D]*/, ''), 10) + 20 + "%"
+
+ barElement.attr("style", "width: #{newWidth}")
+
initialize: (data) ->
- @users = new StaffPlan.Collections.Users data.users
- @projects = new StaffPlan.Collections.Projects data.projects
- @userCompanies = data.userCompanies
- @clients = new StaffPlan.Collections.Clients data.clients
- @assignments = new StaffPlan.Collections.Assignments data.assignments
- @currentCompany = data.currentCompany
- @currentUser = data.currentUser
- @relevantYears = _.reject( _.uniq(_.flatten(StaffPlan.assignments.reduce (memo, assignment) ->
- memo.push _.uniq(assignment.work_weeks.map (week) -> moment(week.get("beginning_of_week")).year())
- memo
- , [])), (year) ->
- year == 1970 # lol don't ask
- )
- year = parseInt(localStorage.getItem("yearFilter"), 10)
- if _.include(@relevantYears, year)
- StaffPlan.assignments.each (assignment) ->
- assignment.set "filteredWeeks", assignment.work_weeks.select (week) ->
- moment(week.get("beginning_of_week")).year() is year
-
- @router = new StaffPlan.Routers.StaffPlan
- users: @users
- projects: @projects
- clients: @clients
- currentCompany: @currentCompany
- currentUser: @currentUser
- $ -> Backbone.history.start(pushState: true)
-
- @checkPresence()
-
-
- $('a:not([data-bypass])').live 'click', (event) =>
- event.preventDefault()
- href = $(event.currentTarget).attr('href').slice(1)
+ # show modal blocker
+ $(document.body).append(
+ '<div class="modal-backdrop"><div class="progress progress-striped"><div class="bar"></div></div></div>'
+ )
+
+ async.parallel([
+ (callback) => @loadAssignments(callback)
+ (callback) => @loadData('users', callback)
+ (callback) => @loadData('projects', callback)
+ (callback) => @loadData('clients', callback)
+ ]
+ =>
+ @addProgress()
+ @companies = new Backbone.Collection data.userCompanies
+ @currentCompany = @companies.get(data.currentCompanyId)
+ @currentUser = @users.get(data.currentUserId)
+ @relevantYears = _.reject( _.uniq(_.flatten(StaffPlan.assignments.reduce (memo, assignment) ->
+ memo.push _.uniq(assignment.work_weeks.map (week) -> moment(week.get("beginning_of_week")).year())
+ memo
+ , [])), (year) ->
+ year == 1970 # lol don't ask
+ )
+ year = parseInt(localStorage.getItem("yearFilter"), 10)
+ if _.include(@relevantYears, year)
+ StaffPlan.assignments.each (assignment) ->
+ assignment.set "filteredWeeks", assignment.work_weeks.select (week) ->
+ moment(week.get("beginning_of_week")).year() is year
+
+ @router = new StaffPlan.Routers.StaffPlan
+ users: @users
+ projects: @projects
+ clients: @clients
+ currentCompany: @currentCompany
+ currentUser: @currentUser
+ $ -> Backbone.history.start(pushState: true)
+
+ @checkPresence()
+
+
+ $('a:not([data-bypass])').live 'click', (event) =>
+ event.preventDefault()
+ href = $(event.currentTarget).attr('href').slice(1)
- ga('send', 'pageview',
- 'page': href
- )
+ unless typeof ga is "undefined"
+ ga('send', 'pageview',
+ 'page': href
+ )
- Backbone.history.navigate(href, true)
+ Backbone.history.navigate(href, true)
+ )
checkPresence: ->
$.ajax
@@ -4,9 +4,9 @@ class StaffPlan.View extends Support.CompositeView
@$el.empty()
@$el.html StaffPlan.Templates.Layouts.application
- currentUserId: StaffPlan.currentUser.id
+ currentUserId: StaffPlan.currentUser.get('id')
- if StaffPlan.userCompanies.length > 1
+ if StaffPlan.companies.length > 1
companySwitcher = new StaffPlan.Views.Shared.CompanySwitcher
@$el.find('header .inner ul:first').append companySwitcher.render().el
@@ -11,15 +11,15 @@ class StaffPlan.Views.Shared.CompanySwitcher extends Backbone.View
event.preventDefault()
event.stopPropagation()
selectedCompanyId = $(event.target).data('company-id')
- user = StaffPlan.users.get StaffPlan.currentUser.id
+ user = StaffPlan.users.get StaffPlan.currentUser.get('id')
user.save {current_company_id: selectedCompanyId},
success: (model, response, options) ->
window.location.href = "/staffplans/#{user.id}"
, error: (model, xhr, options) ->
alert "An error occurred while switching companies. Please try again."
render: ->
@$el.html StaffPlan.Templates.Shared.companySwitcher
- userId: StaffPlan.currentUser.id
- companies: _.select(StaffPlan.userCompanies, (obj) -> (obj.id isnt StaffPlan.currentCompany.id))
- currentCompanyName: StaffPlan.currentCompany.name
+ userId: StaffPlan.currentUser.get("id")
+ companies: StaffPlan.companies.select (obj) -> (obj.id isnt StaffPlan.currentCompany.get("id"))
+ currentCompanyName: StaffPlan.currentCompany.get("name")
@
@@ -49,7 +49,7 @@ class StaffPlan.Views.DateRangeView extends Support.CompositeView
@remove()
render: ->
- displayDates = StaffPlan.users.get(StaffPlan.currentUser.id).preferences.get("display_dates")
+ displayDates = StaffPlan.users.get(StaffPlan.currentUser.get('id')).preferences.get("display_dates")
data = _.map @collection, (timestamp) ->
m = moment(timestamp)
weekNumber = Math.ceil(m.date() / 7)
@@ -34,7 +34,7 @@ class window.StaffPlan.Views.Projects.Edit extends StaffPlan.View
updateProject: (clientId, formValues) ->
# Each model should expose a whitelistedAttributes so that we only transmit what's needed
projectAttributes = _.extend (_.pick formValues.project, ['name', 'active', 'payment_frequency', 'cost']),
- company_id: window.StaffPlan.currentCompany.id
+ company_id: window.StaffPlan.currentCompany.get('id')
client_id: clientId
@model.save projectAttributes,
success: (model, response) ->
@@ -32,7 +32,7 @@ class window.StaffPlan.Views.Projects.New extends StaffPlan.View
createProject: (clientId, formValues) ->
# Each model should expose a whitelistedAttributes so that we only transmit what's needed
projectAttributes = _.extend (_.pick formValues.project, ['name', 'active', 'payment_frequency', 'cost']),
- company_id: window.StaffPlan.currentCompany.id
+ company_id: window.StaffPlan.currentCompany.get('id')
client_id: clientId
@collection.create projectAttributes,
success: (model, response) ->
@@ -36,7 +36,14 @@ class window.StaffPlan.Views.StaffPlans.Show extends StaffPlan.View
items: 12
gatherClientsByAssignments: ->
- _.uniq @model.getAssignments().select((assignment) -> !assignment.get('archived')).map((assignment) -> assignment.get('client_id')).map (clientId) -> StaffPlan.clients.get clientId
+ _.uniq @model.getAssignments()
+ .select((assignment) ->
+ # non-archived
+ !assignment.get('archived')
+ ).map((assignment) ->
+ assignment.get('client_id')
+ ).map (clientId) ->
+ StaffPlan.clients.get clientId
initialize: ->
_.extend @, StaffPlan.Mixins.Events.weeks
@@ -38,8 +38,8 @@ class window.StaffPlan.Views.Users.New extends StaffPlan.View
, {}
@collection.create userAttributes,
success: (model, response) =>
- membership = new window.StaffPlan.Models.Membership {user_id: model.id, company_id: window.StaffPlan.currentCompany.id},
- company_id: window.StaffPlan.currentCompany.id
+ membership = new window.StaffPlan.Models.Membership {user_id: model.id, company_id: window.StaffPlan.currentCompany.get('id')},
+ company_id: window.StaffPlan.currentCompany.get('id')
parent: model
membership.save membershipAttributes,
success: (resource, response) ->
@@ -4,4 +4,10 @@
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require bootstrap
*= require screen
-*/
+*/
+
+.progress {
+ width: 50%;
+ margin: auto;
+ margin-top: 10%;
+}
@@ -1,7 +1,11 @@
class AssignmentsController < ApplicationController
respond_to :json, :html
-
+
+ def index
+ @assignments = Assignment.includes(:work_weeks).where(:project_id => current_user.current_company.projects.map(&:id))
+ end
+
def create
if params[:assignment][:user_id].present?
@target_user = User.where(:id => params[:assignment][:user_id]).first
@@ -6,6 +6,7 @@ class ClientsController < ApplicationController
end
def index
+ respond_with(current_user.current_company.decorate.clients_as_json)
end
def show
@@ -2,7 +2,11 @@ class CompaniesController < ApplicationController
# A user whose sole company was destroyed needs to be able to create one
skip_before_filter :require_current_company
-
+
+ def index
+ render(json: current_user.decorate.companies_as_json)
+ end
+
def new
@company = Company.new
@user = current_user || @company.users.build
@@ -4,6 +4,10 @@ class ProjectsController < ApplicationController
before_filter :find_target, only: [:show, :edit, :update, :destroy]
+ def index
+ render(json: current_user.current_company.decorate.projects_as_json)
+ end
+
def show
end
@@ -4,11 +4,11 @@ class UsersController < ApplicationController
end
def index
- @users = current_user.current_company.users
-
respond_to do |format|
- format.html
- format.json { render json: @users }
+ format.html {}
+ format.json {
+ render(json: current_user.current_company.decorate.users_json)
+ }
end
end
Oops, something went wrong.

0 comments on commit b74061d

Please sign in to comment.