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?
"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
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.