I am working on re-factoring my admittedly ambitious employee management Rails app that I created for work. The good news is, my first major version went over like a dream(With no small amount of thanks due to the community and the support)! All of the functionality the bosses dreamed of! The bad news? It's REALLY SLOW. So I rolled up my sleeves and have been working on some re-writes that are showing a tremendous amount of progress(This is my first major app!) My initial page crunches and loads data from 5 separate tables. There is a lot of logic that goes into supporting the Model the entire app is designed around (appropriately named the DaySchedule object). Within the views there are a lot of calls made from database associations(DaySchedule.employee.full_name, DaySchedule.assignment.assignment_name, you get the idea). These related models are vital for the views, but I know that they are killing my render time . . . I also know that db access in the views is a big no no. I was wondering what others did when faced with this? My thought has been to initialize a bunch of "virtual attributes" when instantiating the DaySchedule object back in the model. (going from DaySchedule.employee.full_name to a DaySchedule.full_name method that I set up with initialize so it is in memory). Does this sound like the right thing to do? What are best practices when an object has a large amount of associations with other models and the view needs access to those related objects?
on 2008-12-08 10:53
on 2008-12-08 11:45
"What are best practices when an object has a large amount of associations with other models and the view needs access to those related objects?" using the :include statement. say we would have two models schedule and employee an employee has_many schedules somewhere in the controller: @employee = Employee.find(:all, params[:id]) do this instead: @employee = Employee.find(:all, params[:id], :include => [:schedules]) Then Rails will load employee and schedules in one go with a SQL JOIN. any line like @employe.schedules.each do |schedule| won't need to access the db anymore
on 2008-12-08 16:50
You just shaved 400ms off my refreshes in development . . . brilliant! Thanks so much!
on 2008-12-08 16:50
BushyMark wrote: > > I was wondering what others did when faced with this? My thought has > been to initialize a bunch of "virtual attributes" when instantiating > the DaySchedule object back in the model. (going from > DaySchedule.employee.full_name to a DaySchedule.full_name method that > I set up with initialize so it is in memory). Does this sound like the > right thing to do? What are best practices when an object has a large > amount of associations with other models and the view needs access to > those related objects? Cache baby, cache... if your initial page views show information that changes infrequently, or groups of information that change infrequently, caching the fragments that make up those views can save you lots of time. Another option is to create a view that marshall's the data in the format you want it and let the database do all the hard work. Caching stuff: In my apps 'show' for any given model, the right side context navigation shows a list of all the related models and provides a hyperlink to each of them. This right side div is composed of a hierarchy of cached fragments (some models have as many as 9 related types of models (call this n), each type with m related model instances). The top level cache is the full context menu, and there are n sub-fragments that make up the top level one. Add/Edit/Delete a related entity, and that sub fragment is invalidated, and the top level fragment also. The next show reads records only to refresh that sub-fragment and then reconstructs the top level fragment from the other fragments. Comparing load times from a cold cache (after a rake tmp:cache:clear), versus a simple redisplay or adding/dropping 1 related model instance yields an order of magnitude difference or more, depending on how many related models there are, and this is all still file-based caching.