Better way to force some classes to be eager loaded in development mode with Rails 3.0.5 and class c

Hi,

Spent a fair number of hours working out this issue and while I have a
working solution I am not happy with it - it feels really really
dirty.

We define a custom ActiveRecord sub-class that is used by a number of
our data models that has a custom self.inherited method to register
the sub-classes with the super class as we have super-class level
operations that iterate across all of the sub-classes - factory-like
class methods.

From our custom sub-class of ActiveRecord::Base

Add all X classes to class-level array for use

in class methods that generate X for all sub-classes.

def self.inherited(klass)
if (klass.class != X) and (klass.class.to_s !~ /^X/)
@@x_classes.push klass
end
# Chain to super or AR classes break!
super(klass)
end

this works really well for our purposes when class caching is on -
however, with class caching off in development mode, the callbacks do
not get called until the classes are first referenced - so if the
super class methods are called that iterate through the class array of
sub-classes before the sub-classes are all referenced, nothing is
returned because no self.inherited calls have happened …

With class caching on the callbacks are called and life is happy.

I have tried a number of solutions to this for development mode:

  • config.prepare_to did not work for this
  • eager_load directives did not work for this
  • config.after_intialize only works for initial load, fails to be
    called on reloead!
  • initializer did not work for this as only called once at startup

So far the only one that works for both the initial load of
development and after reload! is called looks like this (from our
config/environments/development.rb).

The problem of course with this code is that 1) it is horribly ugly
and 2) it undoes the whole intent of the meta-programming when in
development mode - which was to have sub-classes self-register so
that we would not have to explicitly enumerate them and worry about
forgetting to add one should we add another subclass :p.

Any pointers / advice on how to not do it this way but have stuff work
in dev like it does in other environments (works fine with no crazy
code when class caching is true) much appreciated.

  • Max

XXX - workarounds for class_caching == false in development

mode.

Sources for code fixes:

*

http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-rails-3-console/

* Configuring Rails Applications — Ruby on Rails Guides

if Rails.env.development?

Bootstrap classes being referenced as we use meta-programming that

does not get called in development because class caching

is off. Merely accessing the classes by name triggers the

callbacks that otherwise get called immediately with class

caching on in non-development environments.

def bootstrap_x_callbacks
X1.nil?
X2.nil?
X3.nil?
X4.nil?
X5.nil?
X6.nil?
end

Run once on startup after Rails environment is all warmed up and

ready to rock.

MyApp::Application.configure do
config.after_initialize do
bootstrap_x_callbacks
end
end

Schedule it to be called after every reload!

ActionDispatch::Callbacks.after do
bootstrap_x_callbacks
end

end

On May 5, 4:56am, Max S. [email protected] wrote:

development and after reload! is called looks like this (from our
code when class caching is true) much appreciated.
A slightly less horrible variant I’ve used in the past is

class BaseX < …

end
require_dependency ‘sub1’
require_dependency ‘sub2’

which is a little bit less horrible than having a random bootstrap_x
method called in funny places but doesn’t solve the problem of being
easy to forget to add to the list

Fred

Frederick,

On Thu, May 5, 2011 at 2:21 AM, Frederick C.
[email protected] wrote:

end
require_dependency ‘sub1’
require_dependency ‘sub2’

which is a little bit less horrible than having a random bootstrap_x
method called in funny places but doesn’t solve the problem of being
easy to forget to add to the list

well, the bootstrap is not in a random place, it is in
config/environments/development.rb, so the code only runs in
development mode :slight_smile: - and yes, neither is great:

  • Pollute base classes with knowledge of their sub-classes for every
    environment just to fix a development environment behavior
  • Add a bunch of custom code to development.rb to work around the same
    and not have to pollute production code

Both create additional ‘remember to’ tasks that undo a lot of the
benefit the meta-programming is supposed to provide.

  • Max