Webmaster's Notes

Tuesday, March 25, 2008

RoR: Caching Dynamic Association Conditions

The problem which is verbosely described in a previous post on dynamic associations still does not have a clean solution - I've been researching possible workarounds, and there is no definite answer. One feasible workaround is specifying :conditions => 'send(:method)' in single quotes, this way Rails will only eval the conditions when forming the SQL string. This, and what was suggested in my previous post, both would work... Unless you would want to reuse that association with different (or no) conditions later on.

And here comes the trouble - Rails preloads all model classes on startup, and any changes that your controller actions do to the model classes stay cached for all further requests. So on production system, modifying an association in run-time would affect all future references through that association (and that's in fact what has happened to me). We better restore the conditions back after modifying them in with_conditions method. But if your Rails app is anything complicated, it probably uses delayed loading when rendering the views, so you can not reset association conditions right away in the model. Let's delay it until the next request:

class ActiveRecord::Base
@@saved_conds = Hash.new

# dynamically modify conditions as there is no other way in Rails
# to specify run-time conditions on joins...
def self.with_conditions(assoc, conditions)
@@saved_conds[self.to_s] ||= Hash.new
# only save if that's the first call during this request
@@saved_conds[self.to_s][assoc] ||=
reflect_on_association(assoc).options[:conditions]
reflect_on_association(assoc).options[:conditions] = conditions
yield
end

# reset association conditions if any has been modified by our
# with_conditions calls in the previous request
def self.reset_conditions
return if @@saved_conds.empty?
@@saved_conds.each { |klass,associations|
associations.each { |assoc,saved|
model = klass.constantize
model.reflect_on_association(assoc).options[:conditions] = saved
}
}
@@saved_conds = Hash.new
end
end


This solution I came up with is pretty hacky - but it works. If you know of a better way to mark a class for reload in Rails, let me know. This code saves modified conditions in a hash by class and association and then you would need to add code to restore them to a mint condition in a before_ or around_ filter in ApplicationController (call like Magazine.reset_conditions). Using class name as a Hash parameter since class variable behavior in Ruby is strange to say the least - it is shared in all inherited classes and the parent class :)

Labels: , , , ,

Wednesday, February 27, 2008

PHP: XCache Installation

A quick note to self: IBM site has a very nice writeup on installing XCache, a php opcode and variable caching which seems popular lately. Other sources of information are missing all the important details which leads to wasted time. Visit the linked page for details (http://www.ibm.com/developerworks/library/os-php-fastapps1/).

It does not have a walkthrough on configuring xcache options in the php.ini or xcache.ini, but they are self-explanatory if you read comments. Out of practice, variable cache (xcache.var_size) has to be about 10% size of the opcode cache (xcache.size).

Labels: , , ,